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

如何免费建网站软文营销定义

如何免费建网站,软文营销定义,做网站建设的公司排名,网上学设计哪个平台好快速体验 以下是 项目中 已经用slog替换 zap 后的 logger 使用方法,无任何感知,与之前一模一样 package mainimport "github.com/webws/go-moda/logger"func main() {// 格式化打印 {"time":"2023-09-08T01:25:21.31346308:00","level&qu…

快速体验

以下是 项目中 已经用slog替换 zap 后的 logger 使用方法,无任何感知,与之前一模一样

package mainimport "github.com/webws/go-moda/logger"func main() {// 格式化打印 {"time":"2023-09-08T01:25:21.313463+08:00","level":"INFO","msg":"info hello slog","key":"value","file":"/Users/xxx/w/pro/go-moda/example/logger/main.go","line":6}logger.Infow("info hello slog", "key", "value")   // 打印jsonlogger.Debugw("debug hello slog", "key", "value") // 不展示logger.SetLevel(logger.DebugLevel)                // 设置等级logger.Debugw("debug hello slog", "key", "value") // 设置了等级之后展示 debug// withnewLog := logger.With("newkey", "newValue")newLog.Debugw("new hello slog") // 会打印 newkey:newValuelogger.Debugw("old hello slog") // 不会打印 newkey:newValue
}

slog 基础使用

Go 1.21版本中 将 golang.org/x/exp/slog 引入了go标准库 路径为 log/slog。
新项目的 如果不使用第三方包,可以直接用slog当你的 logger

slog 简单示例:

        slog.Info("finished", "key", "value")slog.Debug("finished", "key1", "value1")

以下是打印日志 默认slog 输出级别是info以上,所以debug是打印不出来.

2023/09/08 00:27:24 INFO finished key=value

json格式化,设置日志等级,并打印调用函数和文件

opts := &slog.HandlerOptions{AddSource: true, Level: slog.LevelInfo}logger := slog.New(slog.NewJSONHandler(os.Stdout, opts))logger.Info("finished", "key", "value")

输出

{"time":"2023-09-08T00:34:22.035962+08:00","level":"INFO","source":{"function":"callvis/slog.TestLogJsonHandler","file":"/Users/websong/w/pro/go-note/slog/main_test.go","line":39},"msg":"finished","key":"value"}

原有 logger zap实现

原有的项目已经实现了一套logger,使用zap log 实现接口

原有代码示例

logger interface LoggerInterface

package loggertype LoggerInterface interface {Debugw(msg string, keysAndValues ...interface{})Infow(msg string, keysAndValues ...interface{})Errorw(msg string, keysAndValues ...interface{})Fatalw(msg string, keysAndValues ...interface{})SetLevel(level Level)With(keyValues ...interface{}) LoggerInterface
}

zap log 实现 LoggerInterface

type ZapSugaredLogger struct {logger    *zap.SugaredLoggerzapConfig *zap.Config
}func buildZapLog(level Level) LoggerInterface {encoderConfig := zapcore.EncoderConfig{TimeKey:        "ts",LevelKey:       "level",NameKey:        "logger",CallerKey:      "caller",MessageKey:     "msg",StacktraceKey:  "stacktrace",LineEnding:     zapcore.DefaultLineEnding,EncodeDuration: zapcore.SecondsDurationEncoder,EncodeTime:     zapcore.ISO8601TimeEncoder,EncodeLevel:    zapcore.LowercaseLevelEncoder,EncodeCaller:   zapcore.ShortCallerEncoder,}zapConfig := &zap.Config{Level:             zap.NewAtomicLevelAt(zapcore.Level(level)),Development:       true,DisableCaller:     false,DisableStacktrace: true,Sampling:          &zap.SamplingConfig{Initial: 100, Thereafter: 100},Encoding:          "json",EncoderConfig:     encoderConfig,OutputPaths:       []string{"stderr"},ErrorOutputPaths:  []string{"stderr"},}l, err := zapConfig.Build(zap.AddCallerSkip(2))if err != nil {fmt.Printf("zap build logger fail err=%v", err)return nil}return &ZapSugaredLogger{logger:    l.Sugar(),zapConfig: zapConfig,}func (l *ZapSugaredLogger) Debugw(msg string, keysAndValues ...interface{}) {l.logger.Debugw(msg, keysAndValues...)}func (l *ZapSugaredLogger) Errorw(msg string, keysAndValues ...interface{}) {l.logger.Errorw(msg, keysAndValues...)}// ...省略info 之类其他实现接口的方法 
}

全局初始化logger,因代码量太大,以下是伪代码,主要提供思路,为下文 slog 无侵入替换zap 预热

package logger// 全局 log,也可以单独 NewLogger 获取新的实例
var globalog = newlogger(DebugLevel)func newlogger(level Level) *Logger {l := &Logger{logger: buildZapLog(level)}return l
}
func Infow(msg string, keysAndValues ...interface{}) {globalog.logger.Infow(msg, keysAndValues...)
}
// ...省略其他全局方法,比如DebugW 之类

在项目里就可以通过logger 使用日志

    logger.Debugw("msg1", "k1", "v1") // debuglogger.SetLevel(DebugLevel)      //设置等级logger.Debugw("msg3", "k3", "v3") newLogger := logger.With("name", "song")logger.Infow("msg4", "k4", "v4")  // print

slog 不侵入业务 替换zap

logger interface 接口保持不变

slog 实现 代码

package loggerimport ("log/slog""os""runtime"
)var _ LoggerInterface = (*SlogLogger)(nil)type SlogLogger struct {logger *slog.Loggerlevel  *slog.LevelVar// true 代表使用slog打印文件路径,false 会使用自定的方法给日志 增加字段 file lineaddSource bool
}// newSlog
func newSlog(level Level, addSource bool) LoggerInterface {levelVar := &slog.LevelVar{}levelVar.Set(slog.LevelInfo)opts := &slog.HandlerOptions{AddSource: addSource, Level: levelVar}logger := slog.New(slog.NewJSONHandler(os.Stdout, opts))return &SlogLogger{logger: logger,level:  levelVar,}
}
func (l *SlogLogger) Fatalw(msg string, keysAndValues ...interface{}) {keysAndValues = l.ApppendFileLine(keysAndValues...)l.logger.Error(msg, keysAndValues...)os.Exit(1)
}func (l *SlogLogger) Infow(msg string, keysAndValues ...interface{}) {keysAndValues = l.ApppendFileLine(keysAndValues...)l.logger.Info(msg, keysAndValues...)
}
// 省略继承接口的其他方法 DebugW 之类的
func (l *SlogLogger) SetLevel(level Level) {zapLevelToSlogLevel(level)l.level.Set(slog.Level(zapLevelToSlogLevel(level)))
}
// 
func (l *SlogLogger) With(keyValues ...interface{}) LoggerInterface {newLog := l.logger.With(keyValues...)return &SlogLogger{logger: newLog,level:  l.level,}
}// ApppendFileLine 获取调用方的文件和文件号
// slog 原生 暂不支持 callerSkip,使用此函数啃根会有性能问题,最好等slog提供 CallerSkip 的参数
func (l *SlogLogger) ApppendFileLine(keyValues ...interface{}) []interface{} {l.addSource = falseif !l.addSource {var pc uintptrvar pcs [1]uintptr// skip [runtime.Callers, this function, this function's caller]runtime.Callers(4, pcs[:])pc = pcs[0]fs := runtime.CallersFrames([]uintptr{pc})f, _ := fs.Next()keyValues = append(keyValues, "file", f.File, "line", f.Line)return keyValues}return keyValues
}

全局初始化logger,以下伪代码

package logger
// 全局 log,也可以单独 NewLogger 获取新的实例
var globalog = newlogger(DebugLevel)func newlogger(level Level) *Logger {l := &Logger{logger: newSlog(level, false)}return l
}
func Infow(msg string, keysAndValues ...interface{}) {globalog.logger.Infow(msg, keysAndValues...)
}
// ...省略其他全局方法,比如DebugW 之类

slog 实现 callerSkip 功能

slog 的 addsource 参数 会打印文件名和行号,但 并不能像 zap 那样支持 callerSkip,也就是说 如果将 slog 封装在 logger 目录的log.go 文件下,使用logger进行打印,展示的文件会一只是log.go

看了 slog 的源码,其实slog 使用了 runtime.Callers 在内部实现了 callerSkip 功能,但是没有对外暴露 callerSkip 参数

我就封装了 ApppendFileLine 方法,使用 runtime.Callers 获取到 文件名 和 行号,增加 file 和 line 的key value到日志

可能会有性能问题,希望slog能对外提供一个 callerSkip 参数

    var pc uintptrvar pcs [1]uintptr// skip [runtime.Callers, this function, this function's caller]runtime.Callers(4, pcs[:])pc = pcs[0]fs := runtime.CallersFrames([]uintptr{pc})f, _ := fs.Next()keyValues = append(keyValues, "file", f.File, "line", f.Line)

说明

文章中贴的代码不多,主要提供思路,虽然省略了一些方法和 全局logger的实现方式,也写了两个多小时

如要查看logger实现细节,可查看 在文章开头 快速体验 引用的包 github.com/webws/go-moda/logger

也可以直接看下我这个 仓库 go-moda 里使用 slog 和 zap 的封装

http://www.hkea.cn/news/885070/

相关文章:

  • 天津市建设委员会网站上海网站制作开发
  • 扬中网站建设墨子学院seo
  • 分析电子商务网站建设需求教案青岛今天发生的重大新闻
  • 汕头模板开发建站百度发布信息怎么弄
  • 健身网站开发项目总结关键词筛选工具
  • 重庆网站建设零臻靠谱国内永久免费的云服务器
  • 软件库合集软件资料2024郑州百度快照优化
  • 房地产开发公司网站建设方案seo去哪里学
  • 做网站可以赚钱吗百度小说搜索风云排行榜
  • 做网站交接需要哪些权限网站seo视频教程
  • 在网站怎么做收款二维码刷移动关键词优化
  • 问信息奥赛题怎么做 去哪个网站互联网网络推广
  • b2c电子商务网站系统下载专业网站seo推广
  • 引流推广的方法seo诊断工具
  • 平阴县建设工程网站直通车推广怎么做
  • 网站开发外包不给ftp高佣金app软件推广平台
  • 太原适合网站设计地址百度用户服务中心客服电话
  • 济南源码网站建设长沙网站seo推广公司
  • 北京网站制作17页和业务多一样的平台
  • 无锡市住房城乡建设委网站简单网页设计模板html
  • 武汉市大型的网站制作公司网站ip查询
  • 做仪表行业推广有哪些网站电商网站设计
  • 动静分离网站架构百度售后客服电话24小时
  • 做汽车配件生意的网站佛山seo关键词排名
  • 创意建站推荐百度做广告多少钱一天
  • 巴中网站建设公司百度seo怎么做网站内容优化
  • 查网站备案名称上海网络营销seo
  • 人是用什么做的视频网站网络营销方案设计毕业设计
  • 建设网站考虑因素关键词优化是怎么弄的
  • 陕西营销型网站建设推广普通话的内容简短