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

网站描述怎么修改百度竞价推广计划

网站描述怎么修改,百度竞价推广计划,做dnf辅助官方网站,免费空间做网站Go从入门到精通(21) - 一个简单web项目-统一日志输出 统一日志输出 文章目录Go从入门到精通(21) - 一个简单web项目-统一日志输出前言日志库横向对比zap 使用安装依赖创建日志配置修改主程序的日志在处理函数中使用日志日志示例控制台输出文件输出(json&#xff09…

Go从入门到精通(21) - 一个简单web项目-统一日志输出

统一日志输出


文章目录

  • Go从入门到精通(21) - 一个简单web项目-统一日志输出
  • 前言
  • 日志库横向对比
  • zap 使用
    • 安装依赖
    • 创建日志配置
    • 修改主程序的日志
    • 在处理函数中使用日志
  • 日志示例
    • 控制台输出
    • 文件输出(json)
  • Logger 和 SugaredLogger


前言

在 Go 语言中选择日志库时,需要结合项目规模、性能需求、功能复杂度以及是否需要结构化日志等因素综合考量。


日志库横向对比

特性log/slog(标准库)Zap(Uber)ZerologLogrus
项目背景Go 官方(1.21+ 内置)Uber 开源,工业级实践社区开源,专注极致性能早期主流,社区维护(功能冻结)
结构化日志支持(key-value 原生)支持(Logger 结构化,SugaredLogger 兼容非结构化)强制结构化(JSON 输出,流式 API)支持(字段扩展)
日志级别Debug/Info/Warn/Error 四级Debug/Info/Warn/Error/Dpanic/Panic/Fatal 七级Debug/Info/Warn/Error/Fatal 五级Debug/Info/Warn/Error/Fatal/Panic 六级
性能(写入速度)中(原生实现,无过度优化)极高(预分配内存,非反射序列化)极高(零内存分配,流式构建)中低(反射序列化,内存分配较多)
API 风格类似标准库,简洁直观结构化需显式类型(如 Int、String),Sugared 兼容 fmt 风格链式调用(如 log.Info().Str(“k”,“v”).Msg(“”))类似 fmt,支持 WithFields 扩展
动态级别调整需自定义 Handler 实现(第三方支持)原生支持(通过 AtomicLevel)支持(Level 接口)支持(需手动实现或依赖插件)
日志轮转需依赖第三方 Handler(如 github.com/lmittmann/tint)原生支持(结合 lumberjack 等)需依赖第三方(如 github.com/rs/zerolog/logrotate)需依赖插件(如 github.com/lestrrat-go/file-rotatelogs)
内存分配较少(原生优化)极少(预分配+非反射)几乎零分配(流式构建+栈上操作)较多(反射+动态字段)
扩展能力强(Handler 接口可自定义)强(Core 接口+大量第三方集成)中(输出适配器扩展)强(Hooks 机制+丰富插件)
学习成本低(官方文档完善,类似标准库)中(结构化 API 稍繁琐,Sugared 降低门槛)中(链式 API 需适应)低(类似 fmt,文档丰富)
依赖情况无(标准库内置)无(纯 Go 实现,无额外依赖)无(纯 Go 实现)无(纯 Go 实现)
适用场景新项目首选、减少依赖、基础结构化需求高并发服务、性能敏感场景、功能全面需求内存敏感场景(如嵌入式)、纯结构化日志需求旧项目兼容、依赖生态插件的场景
优势官方维护、稳定性强、无依赖、长期兼容性能顶尖、功能全面、结构化+非结构化双模式零内存分配、极简设计、严格结构化生态成熟、迁移成本低、插件丰富
不足高级功能需第三方扩展(如异步写入)结构化 API 稍繁琐(可通过 Sugared 规避)不支持非结构化日志,灵活性有限性能一般,功能不再更新(仅维护)
  • 新项目首选:slog(官方稳定)或 Zap(性能强、功能全)。
  • 性能敏感场景:Zap 或 Zerolog。
  • 兼容性 / 旧项目:Logrus(短期)或迁移到 slog/Zap(长期)。

zap 使用

这里主要介绍zap使用,接入我们之前的项目

安装依赖

go get -u go.uber.org/zap
go get -u go.uber.org/zap/zapcore

创建日志配置

// logger/logger.go
package loggerimport ("go.uber.org/zap""go.uber.org/zap/zapcore""gopkg.in/natefinch/lumberjack.v2""os""time"
)var Logger *zap.Logger
var Sugar *zap.SugaredLoggerfunc init() {var err error// 配置编码器encoderConfig := zapcore.EncoderConfig{TimeKey:        "ts",LevelKey:       "level",NameKey:        "logger",CallerKey:      "caller",MessageKey:     "msg",StacktraceKey:  "stacktrace",LineEnding:     zapcore.DefaultLineEnding,EncodeLevel:    zapcore.CapitalLevelEncoder,EncodeTime:     zapcore.ISO8601TimeEncoder,EncodeDuration: zapcore.SecondsDurationEncoder,EncodeCaller:   zapcore.ShortCallerEncoder,}// 确定日志级别level := zap.InfoLevelif os.Getenv("ENV") == "development" {level = zap.DebugLevel}// 创建日志目录logDir := "./logs"if _, err := os.Stat(logDir); os.IsNotExist(err) {if err := os.MkdirAll(logDir, 0755); err != nil {panic(fmt.Sprintf("无法创建日志目录: %v", err))}}// 配置文件写入器(使用 lumberjack 实现日志切割)fileWriter := zapcore.AddSync(&lumberjack.Logger{Filename:   logDir + "/app.log",MaxSize:    10,   // 每个日志文件最大 10MBMaxBackups: 30,  // 最多保留 30 个备份MaxAge:     7,   // 最多保留 7 天Compress:   true, // 压缩旧日志})// 配置控制台写入器consoleWriter := zapcore.Lock(os.Stdout)// 创建核心core := zapcore.NewTee(zapcore.NewCore(zapcore.NewJSONEncoder(encoderConfig),fileWriter,level,),zapcore.NewCore(zapcore.NewConsoleEncoder(encoderConfig),consoleWriter,level,),)// 创建 LoggerLogger = zap.New(core, zap.AddCaller(),zap.AddStacktrace(zap.ErrorLevel),zap.Fields(zap.String("service", "user-api")),)// 创建 SugaredLogger(提供更灵活的日志方法)Sugar = Logger.Sugar()// 确保程序退出时刷新日志defer Logger.Sync()Sugar.Infow("日志系统初始化完成", "level", level.String())
}

修改主程序的日志

app.go

package appimport ("github.com/gin-contrib/cors""github.com/gin-gonic/gin"swaggerFiles "github.com/swaggo/files"ginSwagger "github.com/swaggo/gin-swagger""go-web-demo/app/api""go-web-demo/app/utils""go-web-demo/docs""go-web-demo/logger""os"
)func StartApp() error {// 设置为生产模式if os.Getenv("ENV") == "production" {gin.SetMode(gin.ReleaseMode)}// 创建默认引擎,包含日志和恢复中间件router := gin.Default()// 添加自定义中间件:请求日志router.Use(utils.LoggingMiddleware())// 配置CORSrouter.Use(cors.Default())// Swagger文档路由docs.Init("localhost:8082")router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))err := api.InitRouters(router)if err != nil {return err}// 启动服务器port := os.Getenv("PORT")if port == "" {port = "8082"}logger.Sugar.Infow("服务器启动成功", "port", port, "env", os.Getenv("ENV"))if err := router.Run(":" + port); err != nil {logger.Sugar.Fatalw("服务器启动失败", "error", err)}return nil
}

token_utils.go

// 自定义日志中间件
func LoggingMiddleware() gin.HandlerFunc {return func(c *gin.Context) {start := time.Now()// 记录请求信息logger.Sugar.Infow("收到请求","method", c.Request.Method,"path", c.Request.URL.Path,"query", c.Request.URL.RawQuery,"client_ip", c.ClientIP(),"user_agent", c.Request.UserAgent(),)// 处理请求c.Next()// 记录响应信息duration := time.Since(start)logger.Sugar.Infow("请求处理完成","status", c.Writer.Status(),"latency", duration.Seconds(),"bytes", c.Writer.Size(),)}
}

在处理函数中使用日志

// RegisterHandler 注册新用户
func RegisterHandler(c *gin.Context) {var request RegisterRequest// 绑定并验证请求if err := c.ShouldBindJSON(&request); err != nil {logger.Sugar.Warnw("无效请求参数", "error", err.Error(),"body",  c.Request.Body,)c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}// 检查用户名是否已存在for _, user := range users {if user.Username == request.Username {logger.Sugar.Warnw("用户名已存在", "username", request.Username)logger.Logger.Warn("用户名已存在", zap.String("username", request.Username))c.JSON(http.StatusConflict, gin.H{"error": "Username already exists"})return}}// 哈希密码hashedPassword, err := bcrypt.GenerateFromPassword([]byte(request.Password), bcrypt.DefaultCost)if err != nil {logger.Sugar.Errorw("密码哈希失败", "error", err)c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})return}// 创建新用户userID := fmt.Sprintf("%d", nextUserID)nextUserID++user := User{ID:       userID,Username: request.Username,Password: string(hashedPassword),Email:    request.Email,}// 保存用户users[userID] = user// 生成令牌token, err := generateToken(userID)if err != nil {logger.Sugar.Errorw("生成令牌失败", "error", err)c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})return}logger.Sugar.Infow("用户注册成功", "user_id",  userID,"username", request.Username,)c.JSON(http.StatusCreated, TokenResponse{Token: token})
}// 其他处理函数类似...

日志示例

控制台输出

2023-07-15T14:30:00.123+0800 INFO logger/logger.go:65 日志系统初始化完成 {“service”: “user-api”, “level”: “debug”}
2023-07-15T14:30:01.456+0800 INFO main.go:78 服务器启动成功 {“service”: “user-api”, “port”: “8080”, “env”: “development”}
2023-07-15T14:30:05.789+0800 INFO main.go:95 收到请求 {“service”: “user-api”, “method”: “POST”, “path”: “/api/register”, “query”: “”, “client_ip”: “127.0.0.1”, “user_agent”: “curl/7.68.0”}
2023-07-15T14:30:05.901+0800 INFO main.go:104 请求处理完成 {“service”: “user-api”, “status”: 201, “latency”: 0.112, “bytes”: 123}

文件输出(json)

{“ts”:“2023-07-15T14:30:05.789+0800”,“level”:“INFO”,“logger”:“user-api”,“caller”:“main.go:95”,“msg”:“收到请求”,“method”:“POST”,“path”:“/api/register”,“query”:“”,“client_ip”:“127.0.0.1”,“user_agent”:“curl/7.68.0”}
{“ts”:“2023-07-15T14:30:05.901+0800”,“level”:“INFO”,“logger”:“user-api”,“caller”:“main.go:104”,“msg”:“请求处理完成”,“status”:201,“latency”:0.112,“bytes”:123}

这种日志配置既满足开发环境的可读性需求,又适合生产环境的日志收集和分析系统(如ELK)。

Logger 和 SugaredLogger

  1. 性能差异

Logger:

  • 使用类型安全的方法(如 zap.String(key, value)、zap.Int(key, value)),避免反射。
  • 日志构建过程中几乎无内存分配,适合高频调用的关键路径(如 API 处理、循环内部)。

SugaredLogger:

  • 使用 interface{} 类型接收参数,运行时通过反射推断类型,性能略低。
  • 适合低频调用的非关键路径(如初始化日志、异常处理)。
  1. API 风格差异
    每条日志必须显式指定键值对及其类型,确保日志格式统一。
logger.Info("http request processed",zap.String("method", "POST"),zap.Int("status", 200),zap.Duration("elapsed", time.Since(start)),
)

输出结果(JSON 格式):

{
“level”: “info”,
“ts”: 1680000000.123,
“caller”: “main.go:42”,
“msg”: “http request processed”,
“method”: “POST”,
“status”: 200,
“elapsed”: “500.5µs”
}

SugaredLogger(非结构化):
使用类似 fmt.Sprintf 的风格,支持占位符和任意类型参数。

sugar.Info("http request processed: %s %d (%s)","POST", 200, time.Since(start),
)

输出结果(JSON 格式):

{
“level”: “info”,
“ts”: 1680000000.123,
“caller”: “main.go:42”,
“msg”: “http request processed: POST 200 (500.5µs)”
}

  1. 适用场景
  • Logger:
    • 生产环境的核心服务(如 API 网关、数据库操作)。
    • 需要精确控制日志格式和性能的场景。
    • 日志会被 ELK、Prometheus 等系统收集分析(结构化数据更易处理)。
  • SugaredLogger:
    • 开发阶段的快速调试(如打印临时变量)。
    • 日志格式灵活性要求高的场景(如输出复杂对象)。
    • 非关键路径的低频日志(如配置加载、启动信息)。

三、最佳实践
混合使用:

  • 在性能敏感的代码中使用 Logger,在调试或非关键路径使用 SugaredLogger。
  • 避免在循环中使用 SugaredLogger:
    反射开销在高频调用时会显著影响性能。
  • 生产环境优先使用 Logger:
    结构化日志更易于自动化分析和监控告警。
http://www.dtcms.com/wzjs/109061.html

相关文章:

  • 网站排名优化查询cps推广
  • 在线平面图设计seo网站优化案例
  • 做网站做什么公司好交换友情链接的平台有哪些
  • 违法的网址能注册做一网站用吗搜索引擎关键词优化技巧
  • 支付网站费怎么做会计分录友情链接交换系统
  • 武汉骑士网络做网站中央新闻频道直播今天
  • 谁做的怀来吧网站看广告收益的正规平台
  • 网站建设技术方面的论文广告推广 精准引流
  • 什么样的企业要做网站企业网络推广计划
  • 商丘市网站建设公司职业培训机构有哪些
  • 安装了lnmp怎么做网站上海网站营销推广
  • 网站做非经营性广告需备案安徽企业网站建设
  • 如何做彗聪网站呢seo搜索引擎优化实训报告
  • 做简历的什么客网站公司网址
  • 龙城建设网站公司网络推广视频
  • 微信微网站制作教程百度关键词优化推广
  • 网站制作联盟应用市场
  • 海淀区住房和城乡建设委员会官方网站网络广告营销成功案例
  • 西宁做腋臭哪里北大DE网站合肥seo排名优化
  • 查公司信息在哪里查网站推广和seo
  • 中国手工活加工网官网专业网站推广优化
  • 网站设计与规划作业如何交换友情链接
  • 购物网站建设 属于信息系统管理与设计么付费推广外包
  • 短视频变现的15种方法如何推广seo
  • 网站开发毕设设计论文seo营销网站的设计标准
  • 程序员 修电脑 做网站网络营销常用的工具
  • 网站程序开发后怎么上线专业的网站优化公司
  • 网站开发最合适的搭配网站快速排名公司
  • 网站开发课程内部培训广州seo排名优化公司
  • 从0开始做网站网站收录查询爱站