2016-05-27 3 views
0

log15ロガーに属性を追加する必要がありますが、間違って2回追加すると2回表示されます。だから、私は、属性がすでに入力されているかどうかを確認するロジックを追加し、そうであればアクションをスキップします。golang - struct(reflection?)の内部へのアクセス方法

log="&{ctx:[field1 val1 field2 val2 field3 val3 field2 val2] h:0xc82052c1e0}" 

がどのように私はその「CTX」フィールドにアクセスし、自分の価値がすでにあった場合に検証することができます:I出力ログオブジェクトがとき

は、ここで私は何を得るのか?私はいくつかのリフレクトトリックを試して、データ型を取得することができますが、私は値を取得する方法を把握することはできません。

+4

少なくともコードや何かを提供したいと思うかもしれません、あるいはあなたの質問が投票に落ちることになります – Datsik

答えて

1

私が最初にロガーのコンテキストに保存されている属性にアクセスされている、あなたは正確を求め何を通過します。移動中

反射がTypeValueに基づいています。 Typeを使用しているデータにアクセスすることはできません。タイプに関する情報があるだけです(驚きです)。ですから、ここでは反射の側にValueを使用する必要があります。

ただし、ロガーのctxフィールドはエクスポートされないため、直接アクセスすることはできません。しかし、安全でない操作を少し使用すると、それが実行可能になります。ここで

はコードです:

package main 

import (
    "fmt" 
    "reflect" 
    "unsafe" 
) 

type logger struct { 
    ctx []interface{} 
} 

type Logger interface { 
    Populate(ctx ...interface{}) 
} 

func NewLogger() Logger { 
    return &logger{} 
} 

func (l *logger) Populate(ctx ...interface{}) { 
    l.ctx = ctx 
} 

func main() { 
    log := NewLogger() 
    log.Populate(42, "42", 84, "84") 
    fmt.Println(log) 
    // &{[42 42 84 84]} 
    v := reflect.ValueOf(log).Elem() 
    field := v.FieldByName("ctx") 
    ar := *(*[]interface{})(unsafe.Pointer(field.UnsafeAddr())) 

    for _, i := range ar { 
     fmt.Println(i) 
    } 
    // 42 42 84 84 
} 

Go playground

コードが動作すると、あなたは何を期待生成することを決してしないでください。しかし、何をやっていることはサードパーティライブラリのアンエクスポート構造体から値を取得するために反射し、安全でない操作を使用しています。私の英語は正しく表現するのに十分ではありません悪いこれはです。

あなたが最初の場所でそれを2回入れないで、ロガーで二度同じ属性を持ってしたくない場合は、上記のコードを維持するよりもはるかに良いと簡単です。

あなたはまだあなたがロガーに含まれる属性を格納構造体にロガーをラップそして、このために十分な自分を信用していない場合。少なくとも、あなたが手を携えて同じ仕事をすることになるでしょう。

このコードは自由に使用できます。しかし、あなたが自分の好意を持ちたいのであれば、あなたはそれを使用しません。

+2

なぜそれが悪いのかについて:ロガーの内部構造は次のリリースや10リリースから変更されるかもしれません今、完全にあなたのコードを壊す。さらに悪いことに、この変更に対応するためにコードを更新すると、コードの新しいバージョンと古いバージョンのロガーが突然コードが動作しないことがわかります。このバージョンのコードと、互換性のないロガーコードの新しいバージョンが使用される逆の状況は、同じように悪いです。もちろん、それはまったく変わらないかもしれませんが、それは良い考えであるとは限りません。 –

関連する問題