当前位置: 首页 > news >正文

网站做彩票设计网站用什么软件

网站做彩票,设计网站用什么软件,免费模板下载简历,猫窝博客 wordpress提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、log初始化二、log的调用1.logger注入2.引入Helper 三、集成三方框架总结三要#xff1a;五不要 前言 提示#xff1a;这里可以添加本文要记录的大概内容… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 文章目录 前言一、log初始化二、log的调用1.logger注入2.引入Helper 三、集成三方框架总结三要五不要 前言 提示这里可以添加本文要记录的大概内容 例如随着人工智能的不断发展机器学习这门技术也越来越重要很多人都开启了学习机器学习本文就介绍了机器学习的基础内容。 提示以下是本篇文章正文内容下面案例可供参考 一、log初始化 上代码 func main() {flag.Parse()logger : log.With(log.NewStdLogger(os.Stdout),ts, log.DefaultTimestamp,caller, log.DefaultCaller,service.id, id,service.name, Name,service.version, Version,trace.id, tracing.TraceID(),span.id, tracing.SpanID(),)c : config.New(config.WithSource(file.NewSource(flagconf),),)defer c.Close()if err : c.Load(); err ! nil {panic(err)}var bc conf.Bootstrapif err : c.Scan(bc); err ! nil {panic(err)}app, cleanup, err : wireApp(bc.Server, bc.Data, logger)if err ! nil {panic(err)}defer cleanup()// start and wait for stop signalif err : app.Run(); err ! nil {panic(err)} }这是利用Kratos自动生成的项目中的main方法。 这里我们追踪两个方法With、NewStdLogger。 首先看一下接口和结构体 // Logger is a logger interface. type Logger interface {Log(level Level, keyvals ...interface{}) error }type logger struct {logger Loggerprefix []interface{}hasValuer boolctx context.Context }Kratos的接口设计的原则是越少暴露方法后期适配具体框架需要改动的越少。 本质上就是低耦合的思想。 NewStdLogger创建了一个stdLogger的实例stdLogger实现了Logger接口的Log方法所以stdLogger的实例可以作为Logger接口的实现来返回。 type stdLogger struct {log *log.Logger // 这是标准库中的Loggerpool *sync.Pool }// NewStdLogger new a logger with writer. func NewStdLogger(w io.Writer) Logger {return stdLogger{log: log.New(w, , 0),pool: sync.Pool{New: func() interface{} {return new(bytes.Buffer)},},} }其中log.New是go标准库中的方法如下。 // A Logger represents an active logging object that generates lines of // output to an io.Writer. Each logging operation makes a single call to // the Writers Write method. A Logger can be used simultaneously from // multiple goroutines; it guarantees to serialize access to the Writer. type Logger struct {mu sync.Mutex // ensures atomic writes; protects the following fieldsprefix string // prefix on each line to identify the logger (but see Lmsgprefix)flag int // propertiesout io.Writer // destination for outputbuf []byte // for accumulating text to writeisDiscard atomic.Bool // whether out io.Discard } // New creates a new Logger. The out variable sets the // destination to which log data will be written. // The prefix appears at the beginning of each generated log line, or // after the log header if the Lmsgprefix flag is provided. // The flag argument defines the logging properties. func New(out io.Writer, prefix string, flag int) *Logger {l : Logger{out: out, prefix: prefix, flag: flag}if out io.Discard {l.isDiscard.Store(true)}return l }With方法接受一个Logger经过封装再返回一个Logger。 // With with logger fields. func With(l Logger, kv ...interface{}) Logger {c, ok : l.(*logger)if !ok {return logger{logger: l, prefix: kv, hasValuer: containsValuer(kv), ctx: context.Background()}}kvs : make([]interface{}, 0, len(c.prefix)len(kv))kvs append(kvs, c.prefix...)kvs append(kvs, kv...)return logger{logger: c.logger,prefix: kvs,hasValuer: containsValuer(kvs),ctx: c.ctx,} }到这一步我们可以把logger理解成一个大logger套小logger的俄罗斯套娃那么我们再回来看看接口中的唯一一个方法怎么实现的。 func (c *logger) Log(level Level, keyvals ...interface{}) error {kvs : make([]interface{}, 0, len(c.prefix)len(keyvals))kvs append(kvs, c.prefix...)if c.hasValuer {bindValues(c.ctx, kvs)}kvs append(kvs, keyvals...)return c.logger.Log(level, kvs...) }logger经过一些预处理调用子logger的Log所以如开头的代码所示最终会调用到stdLogger的Log实现上代码 // Log print the kv pairs log. func (l *stdLogger) Log(level Level, keyvals ...interface{}) error {if len(keyvals) 0 {return nil}if (len(keyvals) 1) 1 {keyvals append(keyvals, KEYVALS UNPAIRED)}buf : l.pool.Get().(*bytes.Buffer)buf.WriteString(level.String())for i : 0; i len(keyvals); i 2 {_, _ fmt.Fprintf(buf, %s%v, keyvals[i], keyvals[i1])}_ l.log.Output(4, buf.String()) //nolint:gomndbuf.Reset()l.pool.Put(buf)return nil }到这里就好理解了经过层层调用进入了go标准库的go/src/log/log.go的Output方法。 _ l.log.Output(4, buf.String()) //nolint:gomnd 不要做魔法数检查4表示调用深度二、log的调用 1.logger注入 上一节有一行代码 app, cleanup, err : wireApp(bc.Server, bc.Data, logger)这行代码完成了app的初始化并将之前生成的logger注入其中。这里用了wire实现了依赖注入如果是Java转过来可能更容易理解但是不管是否理解依赖注入反正我们知道后续的logger是上一步生成的就可以了。 2.引入Helper // GreeterUsecase is a Greeter usecase. type GreeterUsecase struct {repo GreeterRepolog *log.Helper }// NewGreeterUsecase new a Greeter usecase. func NewGreeterUsecase(repo GreeterRepo, logger log.Logger) *GreeterUsecase {return GreeterUsecase{repo: repo, log: log.NewHelper(logger)} }// CreateGreeter creates a Greeter, and returns the new Greeter. func (uc *GreeterUsecase) CreateGreeter(ctx context.Context, g *Greeter) (*Greeter, error) {uc.log.WithContext(ctx).Infof(CreateGreeter: %v, g.Hello)return uc.repo.Save(ctx, g) } 经过连续的注入这一步进入了HTTP的handler中首先看到NewGreeterUsecase方法通过NewHelper方法将logger转成了log.Helper。 // Helper is a logger helper. type Helper struct {logger LoggermsgKey stringsprint func(...interface{}) stringsprintf func(format string, a ...interface{}) string }进一步CreateGreeter方法在打印日志时调用Helper的WithContext方法获取了一个带有Context的Helper。 代码如下 // WithContext returns a shallow copy of h with its context changed // to ctx. The provided ctx must be non-nil. func (h *Helper) WithContext(ctx context.Context) *Helper {return Helper{msgKey: h.msgKey,logger: WithContext(ctx, h.logger),sprint: h.sprint,sprintf: h.sprintf,} }Infof方法也是Helper结构体的方法由于Helper还实现了Log方法所以Helper也是Logger接口的一个实现所以h.logger.Log会经过一系列调用最终变成调用go标准库的go/src/log/log.go的Output方法。注意这里所说的是在这个示例程序由于开始的时候调用NewStdLogger创建了标准logger很容易想到如果我们最初的log.With中传入的是三方库的接口那么这里是不是就是别的实现了。 现在我们思考一个问题Kratos源码-Java中的日志框架一文中我们看过Java的两种主流日志门面那么Kratos的日志更接近哪一种呢下一节我们继续分析。 // Log Print log by level and keyvals. func (h *Helper) Log(level Level, keyvals ...interface{}) {_ h.logger.Log(level, keyvals...) } // Infof logs a message at info level. func (h *Helper) Infof(format string, a ...interface{}) {_ h.logger.Log(LevelInfo, h.msgKey, h.sprintf(format, a...)) }三、集成三方框架 适配实现 我们已经在contrib/log实现好了一些插件用于适配目前常用的日志库您也可以参考它们的代码来实现自己需要的日志库的适配 std 标准输出Kratos内置 fluent 输出到fluentd zap 适配了uber的zap日志库 aliyun 输出到阿里云日志 下面我们分析一下zap的实现吧。 先看使用 func TestLogger(t *testing.T) {syncer : testWriteSyncer{}encoderCfg : zapcore.EncoderConfig{MessageKey: msg,LevelKey: level,NameKey: logger,EncodeLevel: zapcore.LowercaseLevelEncoder,EncodeTime: zapcore.ISO8601TimeEncoder,EncodeDuration: zapcore.StringDurationEncoder,}core : zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), syncer, zap.DebugLevel)zlogger : zap.New(core).WithOptions()logger : NewLogger(zlogger)defer func() { _ logger.Close() }()zlog : log.NewHelper(logger)zlog.Debugw(log, debug)zlog.Infow(log, info)zlog.Warnw(log, warn)zlog.Errorw(log, error)zlog.Errorw(log, error, except warn)except : []string{{\level\:\debug\,\msg\:\\,\log\:\debug\}\n,{\level\:\info\,\msg\:\\,\log\:\info\}\n,{\level\:\warn\,\msg\:\\,\log\:\warn\}\n,{\level\:\error\,\msg\:\\,\log\:\error\}\n,{\level\:\warn\,\msg\:\Keyvalues must appear in pairs: [log error except warn]\}\n,}for i, s : range except {if s ! syncer.output[i] {t.Logf(except%s, got%s, s, syncer.output[i])t.Fail()}} } 其中可以看到熟悉的影子NewLogger生成loggerNewHelper把logger封装成Helper。 马上我们可以想到如果zap.Logger必然实现了Logger接口中的Log方法上代码 func (l *Logger) Log(level log.Level, keyvals ...interface{}) error {keylen : len(keyvals)if keylen 0 || keylen%2 ! 0 {l.log.Warn(fmt.Sprint(Keyvalues must appear in pairs: , keyvals))return nil}data : make([]zap.Field, 0, (keylen/2)1)for i : 0; i keylen; i 2 {data append(data, zap.Any(fmt.Sprint(keyvals[i]), keyvals[i1]))}switch level {case log.LevelDebug:l.log.Debug(, data...)case log.LevelInfo:l.log.Info(, data...)case log.LevelWarn:l.log.Warn(, data...)case log.LevelError:l.log.Error(, data...)case log.LevelFatal:l.log.Fatal(, data...)}return nil }到这里就清楚了Log方法通过level决定了走zap.log的具体分支也就是Debug、Info、Warn、Error、Fatal。 总结 到此Kratos源码的Logging部分就分析完了。最后插个题外话吧。打印日志应该遵循什么原则。 三要 HTTP、RPC的入参和返回值程序异常原因特殊条件分支 五不要 避免大量数据避免循环避免无意义避免什么也说明不了避免私密 好的日志包括什么 级别-内容-时间-进程名称-类方法名-行号-异常堆栈
http://www.sadfv.cn/news/219471/

相关文章:

  • 营销型网站建设深圳河北省最新任免
  • 深圳好点的网站建设公司顺德做外贸网站
  • 潍坊网页推广制作常州做网站优化
  • 电白区住房和城乡建设部门户网站做网站写需求
  • 网站建设技术有哪些海外服务器租用多少钱一年
  • 网站横条广告长沙网站制作公司哪家好
  • 女装网站欣赏中兴的网站谁做的
  • 华东建设安装有限公司网站南通营销型网站
  • 常德网站建设渠道软件定制平台有哪些
  • 外包做网站需要多少钱电商网站建设电话
  • 温州建网站公司哪家好建立什么指标体系和评价程序规范
  • 普通建站建设销售网站的好处
  • 网站静态页面访问很快php页面访问非常慢怒江网站制作
  • 企业网站源码可以做微信推送的网站
  • 做免费资料分享网站会不会涉及版权WordPress清除文章缓存
  • server 2012 iis 添加网站建设部网站 技术规范
  • 做网站朋友圈广告的文案怎么写专业的内蒙古网站建设
  • 十堰的网站建设公众号开发流程
  • php 网站提速网站推广 公司
  • 手机网站生成app网站建设工资
  • 网站开发项目经验总结教训中国电商网官网
  • 做企业网站设展台设计灵感网站
  • 服务器建设一个自己的网站一般上什么网站
  • 城乡建设举报网站建立网站用英语怎么说
  • 免费货源网站免费版权手工制作小钱包
  • 唐山网站建设外包公司哪家好wordpress 调用评论数量
  • 外贸网站制作费用营口市代做网站
  • 郑州市网站建设怎么样网站首页怎么做
  • 手机网站被拦截怎么解除室内设计接单网站
  • 怎么打帮人 做网站开发的广告购物商城网站