dsbgltg159136540 2016-04-12 21:38
浏览 45

软件包之间共享库时的集中日志记录配置

So I'm using a structured logging library (logrus), and I have a core package used as a base for some other packages, lets call this package me/core, then individual packages like me/foo-service, me/bar-service etc. that use this core library for common dependencies/utilities such as setup, configuration loading, and I also wanted to use it for standardized things like logging, so I want me/core to be able to configure logging for the other packages, with Logrus you can do things like

import(
  log "github.com/Sirupsen/logrus"
)
[...]
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.TextFormatter{FullTimestamp:true})

Then do;

log.Debug("Moo")
log.WithFields(log.Fields{"structured":"data"}).Debug("I have structure data")

getting an output like

> DEBU[2016-04-12T22:11:38+01:00] Moo
> DEBU[2016-04-12T22:11:38+01:00] I have structure data           structured=data

So I want to configure this in my me/foo-service package with something like

import(
  "me/core/logging"
)

func main(){
  logging.Setup()
}

Only for various reasons I'm running into issues. The primary issue seems to be that both me/core, and me/foo-service have a vendored version of the logrus library, those log.Set* commands modify the variable logrus.std logger which holds the standard, global logger, but this is a seperate instance for both packages because me/core/vendor/.../logrus/std and me/foo-service/vendor/.../logrus/std are different objects.

First thing I tried was creating a variable in me/core/logging that I could use in the parent, so something like

package logging

import(
  log "github.com/Sirupsen/logrus"
)

var Log *log.Logger

func Setup(verbose bool){
  Log = log.New()
  if verbose{
    Log.Level = log.DebugLevel
  } else {
    Log.Level = log.InfoLevel
  }
  Log.Formatter = &log.TextFormatter{FullTimestamp:true}
  Log.Debug("Logging verbosely")
}

and that works for simple cases like this

package main

import(
  "me/core/logging"
)

func main() {
  logging.Setup(parsedOptions.Verbose)
  logging.Log.Debug("Moo")
}

However trying to use the structured data Fields causes problems, I can't use the local vendored logrus fields like

logging.Log.WithFields(log.Fields{"data":"hi"}).Debug("test")

as I get

cannot use "me/foo-service/vendor/github.com/Sirupsen/logrus".Fields literal (type "me/foo-service/vendor/github.com/Sirupsen/logrus".Fields) as type "me/core/vendor/github.com/Sirupsen/logrus".Fields in argument to logging.Log.WithFields

And trying to mirror the field in me/core/logging with something like

type Fields log.Fields

Doesn't work ether because it's still a different type

cannot use logging.Fields literal (type logging.Fields) as type "me/core/vendor/github.com/Sirupsen/logrus".Fields in argument to logging.Log.WithFields

I also can't think of any way to pass my local log.std from me/foo-service to me/core as it's also a different type due to the vendored package.

My work around for the moment involves creating a mirror of every method, so in me/core/logging I have a set up like

package logging

import(
  log "github.com/Sirupsen/logrus"
)

var Log *log.Logger
type Fields map[string]interface{}

func Setup(verbose bool){
  Log = log.New()
  if verbose{
    Log.Level = log.DebugLevel
  } else {
    Log.Level = log.InfoLevel
  }
  Log.Formatter = &log.TextFormatter{FullTimestamp:true}
  Log.Debug("Logging verbosely")
}

func Debug(msg interface{}){
  Log.Debug(msg)
}

func WithFields(fields Fields) *log.Entry{
  lf := log.Fields{}
  for k,v := range fields{
    lf[k] = v
  }
  return Log.WithFields(lf)
}

But that would involve creating a mirror for every method which seems really inefficient.

So I'd like a suggestion for how I can make me/core/vendor/.../logrus/std avaliable to me/foo-service, or if I'm thinking about this in completely the wrong way a better way to do it.

  • 写回答

1条回答 默认 最新

  • dsfovbm931034814 2016-04-13 11:30
    关注

    You can only mirror WithFields since the other ones accept built in types. Also since logging.Fields and logrus.Fields are the same type you could more simply do

    func WithFields(f Fields) log.*Entry {
        return Log.WithFields(log.Fields(f))
    }
    

    Then in your service, you could call

    logging.Log.Debug("message")
    logging.WithFields(logging.Fields{"k":"v"}).Debug("message")
    
    评论

报告相同问题?

悬赏问题

  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算