详解Go语言中配置文件使用与日志配置

目录
  • 项目结构调整
  • 配置文件使用
  • 日志配置
  • 小结

接着上一篇的文章构建的项目:Go语学习笔记 - 环境安装、接口测试

只是简单的把GET和POST接口的使用测试了一下。

我还是想按照正常的项目结构调整一下,这篇笔记主要是三个部分:调整项目目录结构、增加配置文件使用、增加日志配置,很常规而且也是每个项目都需要用到的。

项目地址:github地址

项目结构调整

说先对项目目录结构调整一下,按照我自己的开发习惯,增加了几个目录。

项目结构如下图:

解释一下目录结构

  • app/constants:主要放置一些常量
  • app/controllers:控制层,熟悉java的不多说。
  • app/errors:异常定义目录
  • app/pojo:结构体定义文件,主要是接口请求的结构体和接口返回的结构体,或者自定义的结构体。
  • app/router:路由文件
  • app/services:服务实现逻辑目录
  • app/utils:工具文件目录
  • config/log:日志配置文件目录,后面会讲到怎么使用。
  • config/toml:配置文件使用,后面会讲到怎么使用。
  • main.go作为程序的主入口。

配置文件使用

在我们项目结构中,经常会使用到配置文件。配置文件里面会记录像mysql用户名、端口、redis配置信息等等内容。下面先配置一下toml_config.go,来对config.toml配置文件读取。

下面是toml_config.go的内容

package toml

import (
    "fmt"
    "github.com/spf13/viper"
)

type TomlConfig struct {
    AppName string
    Log     LogConfig
}

// 日志保存地址
type LogConfig struct {
    Path  string
    Level string
}

var c TomlConfig

func init() {
    // 设置文件名
    viper.SetConfigName("config")
    // 设置文件类型
    viper.SetConfigType("toml")
    // 设置文件路径,可以多个viper会根据设置顺序依次查找
    viper.AddConfigPath(".")
    viper.AutomaticEnv()
    err := viper.ReadInConfig()
    if err != nil {
        panic(fmt.Errorf("fatal error config file: %s", err))
    }

    viper.Unmarshal(&c)
}
func GetConfig() TomlConfig {
    return c
}

需要安装几个库,命令如下:

go get github.com/natefinch/lumberjack
go get go.uber.org/zap/zapcore

注意,在go文件中,init方法在加载该文件所在包的时候会默认执行。

我们看一下配置的内容,主要是日志级别和存放地址。

验证的话,等下面日志配置好了一起看一下。

日志配置

下面继续配置一下日志,也可以看到配置文件里面配置的日志级别和存放地址都是日志的配置项。

主要在config/log下的logger.go文件,配置了日志相关内容。

logger.go的内容如下

package log

import (
    "os"

    "github.com/natefinch/lumberjack"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
)

type Field = zap.Field

var (
    Logger  *zap.Logger
    String  = zap.String
    Any     = zap.Any
    Int     = zap.Int
    Float32 = zap.Float32
)

// logpath 日志文件路径
// loglevel 日志级别
func InitLogger(logpath string, loglevel string) {
    // 日志分割
    hook := lumberjack.Logger{
        Filename:   logpath, // 日志文件路径,默认 os.TempDir()
        MaxSize:    100,     // 每个日志文件保存100M,默认 100M
        MaxBackups: 30,      // 保留30个备份,默认不限
        MaxAge:     7,       // 保留7天,默认不限

        Compress: true, // 是否压缩,默认不压缩
    }
    write := zapcore.AddSync(&hook)
    // 设置日志级别
    // debug 可以打印出 info debug warn
    // info  级别可以打印 warn info
    // warn  只能打印 warn
    // debug->info->warn->error
    var level zapcore.Level
    switch loglevel {
    case "debug":
        level = zap.DebugLevel
    case "info":
        level = zap.InfoLevel
    case "error":
        level = zap.ErrorLevel
    case "warn":
        level = zap.WarnLevel
    default:
        level = zap.InfoLevel
    }
    encoderConfig := zapcore.EncoderConfig{
        TimeKey:        "time",
        LevelKey:       "level",
        NameKey:        "logger",
        CallerKey:      "linenum",
        MessageKey:     "msg",
        StacktraceKey:  "stacktrace",
        LineEnding:     zapcore.DefaultLineEnding,
        EncodeLevel:    zapcore.LowercaseLevelEncoder,  // 小写编码器
        EncodeTime:     zapcore.ISO8601TimeEncoder,     // ISO8601 UTC 时间格式
        EncodeDuration: zapcore.SecondsDurationEncoder, //
        EncodeCaller:   zapcore.FullCallerEncoder,      // 全路径编码器
        EncodeName:     zapcore.FullNameEncoder,
    }
    // 设置日志级别
    atomicLevel := zap.NewAtomicLevel()
    atomicLevel.SetLevel(level)

    var writes = []zapcore.WriteSyncer{write}
    // 如果是开发环境,同时在控制台上也输出
    if level == zap.DebugLevel {
        writes = append(writes, zapcore.AddSync(os.Stdout))
    }
    core := zapcore.NewCore(
        zapcore.NewConsoleEncoder(encoderConfig),
        // zapcore.NewJSONEncoder(encoderConfig),
        zapcore.NewMultiWriteSyncer(writes...), // 打印到控制台和文件
        // write,
        level,
    )
    // 开启开发模式,堆栈跟踪
    caller := zap.AddCaller()
    // 开启文件及行号
    development := zap.Development()
    // 设置初始化字段,如:添加一个服务器名称
    filed := zap.Fields(zap.String("application", "test-gin"))
    // 构造日志
    Logger = zap.New(core, caller, development, filed)
    Logger.Info("Logger init success")
}

需要安装依赖包,命令如下

go get github.com/spf13/viper

在main.go文件增加logger的初始化加载,看看配置文件和日志是否都生效了。

main.go增加下面的代码

看一下执行的日志

2022-05-31T21:27:54.964+0800    info   D:/goProject/learn-gin/config/log/logger.go:90 Logger init success    {"application": "test-gin"}
2022-05-31T21:27:54.964+0800   info   D:/goProject/learn-gin/main.go:31  hahahah    {"application": "test-gin"}
2022-05-31T21:27:54.964+0800   info   D:/goProject/learn-gin/main.go:32  config {"application": "test-gin", "config": {"AppName":"learn-gin","Log":{"Path":"logs/learn.log","Level":"debug"}}}

可以看到配置文件内容的打印,还有日志的打印效果,OK,舒服了。

小结

这有几个点要注意下:

1、init()和main()方法是golang默认的两个方法,不需要我们调用,程序执行会自动寻找项目中的这俩方法。如果引入了一个包,会优先执行引入包的init方法,再执行自己包内的init方法。

2、如果go项目构建是报错:missing go.sum entry for module providing package xxxxx

执行一下命令:

go build -mod=mod

到此这篇关于详解Go语言中配置文件使用与日志配置的文章就介绍到这了,更多相关Go语言日志配置内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • GO语言ini配置文件的读取的操作

    iniconf 博主前两天在写一个小的go语言项目,想找一个读取ini格式配置和的三方库,在网上找了一圈感觉都不是很好用, 使用起来非常的奇怪,于是自己写了一版,还有两个接口没有实现,在项目中修改或删除配置项后更新到文件中,等待后续有时间了再写,希望用的朋友感觉不错点个赞 github 地址 描述 使用iniconf更简单的读取go的ini配置文件以及根据特定格式的各种配置文件. 安装方法 go get github.com/clod-moon/goconf 使用方法 ini配置文件格式样列 [

  • golang读取各种配置文件(ini、json、yaml)

    目录 viper读取ini文件 viper读取json文件 viper读取yaml文件 日常项目中,读取各种配置文件是避免不了的,这里介绍一个能读取多种配置文件的库,viper viper读取ini文件 config := viper.New() config.AddConfigPath("./conf/") // 文件所在目录 config.SetConfigName("b") // 文件名 config.SetConfigType("ini"

  • Golang打包配置文件的实现示例

    目录 背景 实现 工具 打包 调用 总结 众所周知,Golang 适合写 CLI 工具,但你可能还不知道 Golang 还可以打包配置文件. 背景 最近在写一个涉及到管理阿里云 ECS 的 CLI 工具,这里当然就要考虑阿里云资源使用的安全性了,要求阿里云账号的 AccessKeyId 和 AccessKeySecret 不能下发给 CLI 工具的使用者. 所以这里选择将一份包含 AccessKeyId 和 AccessKeySecret 的配置文件打包进了 CLI 工具中,CLI 工具的使用者

  • 使用Go语言实现配置文件热加载功能

    说到配置文件热加载,这个功能在很多框架中都提供了,如beego,实现的效果就是当你修改文件后,会把你修改后的配置重新加载到配置文件中,而不用重启程序,这个功能在日常中还是非常实用的,毕竟很多时候,线上的配置文件不是想改就能改的. 这次就自己实现一个配置文件的热加载功能的包,并通过一个简单的例子对完成的包进行使用验证 配置文件热加载包的是实现 其实整体的思路还是比较简单的,当获取配置文件内容后,会开启一个goroutine,去 循环读配置文件,当然这里不可能不限制的一直循环,而是设置了一个定时器,

  • 详解Go语言中配置文件使用与日志配置

    目录 项目结构调整 配置文件使用 日志配置 小结 接着上一篇的文章构建的项目:Go语学习笔记 - 环境安装.接口测试 只是简单的把GET和POST接口的使用测试了一下. 我还是想按照正常的项目结构调整一下,这篇笔记主要是三个部分:调整项目目录结构.增加配置文件使用.增加日志配置,很常规而且也是每个项目都需要用到的. 项目地址:github地址 项目结构调整 说先对项目目录结构调整一下,按照我自己的开发习惯,增加了几个目录. 项目结构如下图: 解释一下目录结构 app/constants:主要放置

  • 详解Go语言中关于包导入必学的 8 个知识点

    1. 单行导入与多行导入 在 Go 语言中,一个包可包含多个 .go 文件(这些文件必须得在同一级文件夹中),只要这些 .go 文件的头部都使用 package 关键字声明了同一个包. 导入包主要可分为两种方式: 单行导入 import "fmt" import "sync" 多行导入 import( "fmt" "sync" ) 如你所见,Go 语言中 导入的包,必须得用双引号包含,在这里吐槽一下. 2. 使用别名 在一些场

  • 详解R语言中生存分析模型与时间依赖性ROC曲线可视化

    R语言简介 R是用于统计分析.绘图的语言和操作环境.R是属于GNU系统的一个自由.免费.源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具. 人们通常使用接收者操作特征曲线(ROC)进行二元结果逻辑回归.但是,流行病学研究中感兴趣的结果通常是事件发生时间.使用随时间变化的时间依赖性ROC可以更全面地描述这种情况下的预测模型. 时间依赖性ROC定义 令 Mi为用于死亡率预测的基线(时间0)标量标记. 当随时间推移观察到结果时,其预测性能取决于评估时间 t.直观地说,在零时间测量的标记值应该

  • 详解R语言中的多项式回归、局部回归、核平滑和平滑样条回归模型

    在标准线性模型中,我们假设 .当线性假设无法满足时,可以考虑使用其他方法. 多项式回归 扩展可能是假设某些多项式函数, 同样,在标准线性模型方法(使用GLM的条件正态分布)中,参数  可以使用最小二乘法获得,其中  在  . 即使此多项式模型不是真正的多项式模型,也可能仍然是一个很好的近似值 .实际上,根据 Stone-Weierstrass定理,如果  在某个区间上是连续的,则有一个统一的近似值  ,通过多项式函数. 仅作说明,请考虑以下数据集 db = data.frame(x=xr,y=y

  • 详解R语言中的表达式、数学公式、特殊符号

      在R语言的绘图函数中,如果文本参数是合法的R语言表达式,那么这个表达式就被用Tex类似的规则进行文本格式化. y <- function(x) (exp(-(x^2)/2))/sqrt(2*pi) plot(y, -5, 5, main = expression(f(x) == frac(1,sqrt(2*pi))*e^(-frac(x^2,2))), lwd = 3, col = "blue") library(ggplot2) x <- seq(0, 2*pi, b

  • 详解C语言中不同类型的数据转换规则

    不同类型数据间的混合运算与类型转换 1.自动类型转换 在C语言中,自动类型转换遵循以下规则: ①若参与运算量的类型不同,则先转换成同一类型,然后进行运算 ②转换按数据长度增加的方向进行,以保证精度不降低.如int型和long型运算时,先把int量转成long型后再进行运算 a.若两种类型的字节数不同,转换成字节数高的类型 b.若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型 ③所有的浮点运算都是以双精度进行的,即使是两个float单精度量运算的表达式,也要先转换成double

  • 详解C语言中二分查找的运用技巧

    目录 基础的二分查 查找左侧边界 查找右侧边界 二分查找问题分析 实例1: 爱吃香蕉的珂珂 实例2:运送包裹 前篇文章聊到了二分查找的基础以及细节的处理问题,主要介绍了 查找和目标值相等的元素.查找第一个和目标值相等的元素.查找最后一个和目标值相等的元素 三种情况. 这些情况都适用于有序数组中查找指定元素 这个基本的场景,但实际应用中可能不会这么直接,甚至看了题目之后,都不会想到可以用二分查找算法来解决 . 本文就来分析下二分查找在实际中的应用,通过分析几个应用二分查找的实例,总结下能使用二分查

  • 详解Go语言中的数据类型及类型转换

    目录 1.基本数据类型 2.基础数据类型转换 3.基本数据类型转为字符串 4.strconv的使用 5.字符串转为基础类型 1.基本数据类型 数据类型有很多,先研究一下基础的,例如:布尔型.数字类型.字符串类型. 数字类型有uint8.uint16.uint32.uint64.int8.int16.int32.int64(uint和int区别在于uint为无符号整数,即只支持正数,不支持负数形式) 数字浮点型有fload32.float64.complex64.complex126(后面两个均为

  • 详解Go语言中的作用域和变量隐藏

    目录 前言 包隐藏 全局变量 类型强制 闭包 := 的情况 总结 前言 变量隐藏在 Go 中可能会令人困惑,让我们尝试弄清楚. package main import ( "fmt" "io/ioutil" "log" ) func main() { f, err := ioutil.TempFile("", "") if err != nil { log.Fatal(err) } defer f.Clos

  • 详解Go语言中泛型的实现原理与使用

    目录 前言 问题 解决方法 类型约束 重获类型安全 泛型使用场景 性能 虚拟方法表 单态化 Go 的实现 结论 前言 原文:A gentle introduction to generics in Go byDominik Braun 万俊峰Kevin:我看了觉得文章非常简单易懂,就征求了作者同意,翻译出来给大家分享一下. 本文是对泛型的基本思想及其在 Go 中的实现的一个比较容易理解的介绍,同时也是对围绕泛型的各种性能讨论的简单总结.首先,我们来看看泛型所解决的核心问题. 问题 假设我们想实现

随机推荐