Как стандартизировать поля go-kit/комплект/журнал

# #go #logging #naming-conventions

Вопрос:

Проблема

интерфейс ведения журнала go-kit/log прост и приятен

 type Logger interface {
    Log(keyvals ...interface{}) error
}
 

Но люди склонны думать по-разному и называть одни и те же вещи разными именами.

Я вижу в коде, что одно поле для текста ошибки называется «ошибка», а другое «ошибка». Это затрудняет поиск журналов. Вы должны искать как «ошибку», так и «ошибку» одновременно. Это также может иметь место для полей «msg» или «сообщение».

Есть ли какой-либо способ стандартизировать такое именование?

Ответ №1:

Я вижу три варианта решения этой проблемы:

  1. Официальное соглашение внутри команды и линтер для его проверки
  2. Общий пакет тегов для имен полей журнала, объявленных как const (пример пакета ext в opentracing-go). Команда всегда использует его для Log(ext.Message, "log message text", ext.Error, err) звонков.
  3. Синтаксический сахар, который скрывает название поля внутри. Это может выглядеть так (живой пример)
     // pakage loghelper
    func Err(err error) []interface{} {
        return []interface{}{"err", err}
    }
    
    func Msg(s string) []interface{} {
        return []interface{}{"msg", s}
    }
    
    func KV(items ...interface{}) []interface{} {
        var kv []interface{}
        for _, item := range items {
            switch v := item.(type) {
            default:
                kv = append(kv, v)
            case []interface{}:
                kv = append(kv, v...)
            }
        }
        return kv
    }
    
    // USAGE

    // package main
    import lh ./loghelper
    cid = "42"
    logger.Log(lh.KV(
      lh.Msg("log message text"), 
      lh.Err(errors.New("error-test")), 
      "customer.id", cid
    )...)
 

Ответ №2:

Я бы нашел шаблон конструктора более чистым и читаемым:

 type KVBuilder struct {
    KeyVals []interface{}
}

func NewKVBuilder() *KVBuilder {
    return amp;KVBuilder{}
}

func (k *KVBuilder) Err(err error) *KVBuilder {
    return k.KV("err", err)
}

func (k *KVBuilder) Msg(msg string) *KVBuilder {
    return k.KV("msg", msg)
}

func (k *KVBuilder) KV(kv ...interface{}) *KVBuilder {
    k.KeyVals = append(k.KeyVals, kv...)
    return k
}
 

Используя его:

 var logger Logger

logger.Log(NewKVBuilder().
    Err(errors.New("foo")).
    Msg("bar").
    KV("some", "other").
    KeyVals...,
)
 

И если вы добавите другой метод к KVBuilder :

 func (k *KVBuilder) LogTo(logger Logger) error {
    return logger.Log(k.KeyVals...)
}
 

Вы также можете использовать его следующим образом:

 NewKVBuilder().
    Err(errors.New("foo")).
    Msg("bar").
    KV("some", "other").
    LogTo(logger)
 

Комментарии:

1. Хороший вариант. Спасибо, что поделились!