【源码阅读】osproxy对象存储分布式代理(2)--初始化底层服务和日志器

文章目录

  • 初始化底层服务
    • 函数返回类型
      • APP
      • Redis
    • newLangGoConfig()函数
    • initLangGoConfig()函数
  • 初始化日志器


  • 上一章【源码阅读】osproxy对象存储分布式代理(1)
  • 下一章

  这部分涉及了对于底层服务的初始化和日志器的初始化两部分

// 初始化底层服务,如数据库等
lgConfig := bootstrap.NewConfig("conf/config.yaml")
// 初始化日志器
lgLogger := bootstrap.NewLogger()

初始化底层服务

NewConfig的代码如下

unc NewConfig(confFile string) *config.Configuration {// 如果配置已经生效了,就直接沿用配置if lgConfig.Conf != nil {return lgConfig.Conf} else {// 初始化配置,包括Configuration结构体和一个同步原语lgConfig = newLangGoConfig()// 如果用户没有指定配置文件的路径,则使用系统定义的默认路径"conf/config.yaml"if confFile == "" {lgConfig.initLangGoConfig(confFilePath)} else { //否则使用用户给定的配置文件来初始化lgConfig.initLangGoConfig(confFile)}return lgConfig.Conf}
}

函数返回类型

  NewConfig函数接收一个字符串类型,返回一个*config.Configuration类型,关于这个类型的定义如下

type Configuration struct {App      App                 `mapstructure:"app" json:"app" yaml:"app"`Log      Log                 `mapstructure:"log" json:"log" yaml:"log"`Database []*plugins.Database `mapstructure:"database" json:"database" yaml:"database"`Redis    *plugins.Redis      `mapstructure:"redis" json:"redis" yaml:"redis"`Minio    *plugins.Minio      `mapstructure:"minio" json:"minio" yaml:"minio"`Cos      *plugins.Cos        `mapstructure:"cos" json:"cos" yaml:"cos"`Oss      *plugins.Oss        `mapstructure:"oss" json:"oss" yaml:"oss"`Local    *plugins.Local      `mapstructure:"local" json:"local" yaml:"local"`
}

  *config.Configuration内部也包含了许多自定义的结构体,由许多自定义类型,后面的mapstructure 标签需对应 config.yaml 中的配置名称

APP

type App struct {Env     string `mapstructure:"env" json:"env" yaml:"env"`Port    string `mapstructure:"port" json:"port" yaml:"port"`AppName string `mapstructure:"app_name" json:"app_name" yaml:"app_name"`AppUrl  string `mapstructure:"app_url" json:"app_url" yaml:"app_url"`
}

  其对应的配置文件config.yaml中对应内容为

app:env: prodport: 8888                # 服务端口app_name: osproxy         # 服务名称app_url: http://127.0.0.1

  也就是说,我们首先在App App `mapstructure:"app" json:"app" yaml:"app"` 匹配到app这个配置,获取其中env,port,app_name,app_url等字段,然后复制给结构体APP的变量Env,Port,AppName,AppUrl

Redis

type Redis struct {Host     string `mapstructure:"host" json:"host" yaml:"host"`Port     string `mapstructure:"port" json:"port" yaml:"port"`DB       int    `mapstructure:"db" json:"db" yaml:"db"`Password string `mapstructure:"password" json:"password" yaml:"password"`
}
redis:host: 127.0.0.1        # 服务地址port: 6379             # 服务端口db: 0                  # 库选择password: 123456       # 密码

  对于Redis也是如此,此处对于其他结构体就不在赘述,总的来说,config.Configuration这个结构体中包括了项目中一些基础服务的配置信息。

newLangGoConfig()函数

func newLangGoConfig() *LangGoConfig {return &LangGoConfig{Conf: &config.Configuration{},Once: &sync.Once{},}
}
type LangGoConfig struct {Conf *config.ConfigurationOnce *sync.Once
}

  newLangGoConfig函数用于初始化Configuration结构体和一个同步原语,同步原语sync.Once只有一个导出的方法,即 Do,该方法接收一个函数参数。在 Do 方法被调用后,该函数将被执行,而且只会执行一次,即使在多个协程同时调用的情况下也是如此,提供一个优雅且并发安全的资源初始化方式。
  sync.Once内部为一个互斥锁,用于对指定函数进行加锁操作,具体源码分析在此

initLangGoConfig()函数

func (lg *LangGoConfig) initLangGoConfig(confFile string) {// 基于并发原语对初始化进行并发控制,针对并发场景下的线程安全lg.Once.Do(func() {initConfig(lg.Conf, confFile)},)
}

  这里就是对并发原语Once的使用,它使用Do的方式使得initconfig函数唯一执行。既确保了配置文件的初始化在多线程的环境下只进行一次,也确保了只有在初始化后,才会调用这些配置信息。

// 根据配置文件初始化底层依赖的配置
func initConfig(conf *config.Configuration, confFile string) {pflag.StringVarP(&configPath, "conf", "", filepath.Join(rootPath, confFile),"config path, eg: --conf config.yaml")if !filepath.IsAbs(configPath) {configPath = filepath.Join(rootPath, configPath)}//lgLogger.Logger.Info("load config:" + configPath)fmt.Println("load config:" + configPath)v := viper.New()v.SetConfigFile(configPath)v.SetConfigType("yaml")// 使用viper库读取配置文件if err := v.ReadInConfig(); err != nil {//lgLogger.Logger.Error("read config failed: ", zap.String("err", err.Error()))// 读取失败并返回日志信息fmt.Println("read config failed: ", zap.String("err", err.Error()))panic(err)}// 解析配置文件if err := v.Unmarshal(&conf); err != nil {//lgLogger.Logger.Error("config parse failed: ", zap.String("err", err.Error()))fmt.Println("config parse failed: ", zap.String("err", err.Error()))}// 启动对于文件的监控v.WatchConfig()// 使用viper及时加载文件的变化v.OnConfigChange(func(in fsnotify.Event) {//lgLogger.Logger.Info("", zap.String("config file changed:", in.Name))fmt.Println("", zap.String("config file changed:", in.Name))defer func() {if err := recover(); err != nil {//lgLogger.Logger.Error("config file changed err:", zap.Any("err", err))fmt.Println("config file changed err:", zap.Any("err", err))}}()if err := v.Unmarshal(&conf); err != nil {//lgLogger.Logger.Error("config parse failed: ", zap.String("err", err.Error()))fmt.Println("config parse failed: ", zap.String("err", err.Error()))}})lgConfig.Conf = conf
}

  以上代码便是将配置文件conf.yaml载入系统的过程。值得注意的是作者在这里设置了viper的WatchConfig()函数来实现了配置的热更新。

初始化日志器

NewLogger()的源码如下

func NewLogger() *LangGoLogger {if lgLogger.Logger != nil {return lgLogger} else {lgLogger = newLangGoLogger()lgLogger.initLangGoLogger(lgConfig.Conf)return lgLogger}
}

此处定义的结构体LangGoLogger和上面的LangGoConfig差不多,是一个zap库的logger加上一个同步原语。

type LangGoLogger struct {Logger *zap.LoggerOnce   *sync.Once
}

接下来的代码也差不多,就是对日志库的logger对象进行初始化,并通过同步原语对其进行控制

// NewLogger 生成新Logger
func NewLogger() *LangGoLogger {if lgLogger.Logger != nil {return lgLogger} else {lgLogger = newLangGoLogger()lgLogger.initLangGoLogger(lgConfig.Conf)return lgLogger}
}
// initLangGoLogger 初始化全局log
func (lg *LangGoLogger) initLangGoLogger(conf *config.Configuration) {lg.Once.Do(func() {lg.Logger = initializeLog(conf)},)
}
func initializeLog(conf *config.Configuration) *zap.Logger {// 创建根目录createRootDir(conf)// 设置日志等级setLogLevel(conf)if conf.Log.ShowLine {options = append(options, zap.AddCaller())}// 初始化zapreturn zap.New(getZapCore(conf), options...)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/48170.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

d3d12.dll 文件缺失如何解决?五种修复丢失问题的方法

d3d12.dll 文件缺失如何解决?它为什么会不见呢?今天,我们将探讨 d3d12.dll 文件的重要性、原因以及丢失时的解决策略。本文将全面介绍 d3d12.dll 文件,并提供五种修复丢失问题的方法。 d3d12.dll文件是什么的详细介绍 d3d12.dll …

6 回归集成:xgb、lgb、cat

这个代码是从kaggle上拷贝过来的: 如何使用三个树模型模块化训练;文本特征如何做,如何挖掘;时间特征的处理;模型权重集成; import pandas as pd import math import numpy as np import joblib import…

【JS逆向课件:第八课:异常处理】

异常处理 首先我们要理解什么叫做**"异常”**? 在程序运行过程中,总会遇到各种各样的问题和错误。有些错误是我们编写代码时自己造成的: 比如语法错误、调用错误,甚至逻辑错误。 还有一些错误,则是不可预料的错误…

vst 算法R语言手工实现 | Seurat4 筛选高变基因的算法

1. vst算法描述 (1)为什么需要矫正 image source: https://ouyanglab.com/singlecell/basic.html In this panel, we observe that there is a very strong positive relationship between a gene’s average expression and its observed variance. I…

OpenAI 推出 GPT-4o mini,一种更小、更便宜的人工智能模型

OpenAI 最近推出了新型人工智能模型 GPT-4o mini,以其较小体积和低成本受到关注。这款模型在文本和视觉推理任务上性能优越,且比现有小型模型更快、更经济。GPT-4o mini 已向开发者和消费者发布,企业用户将在下周获得访问权限。 喜好儿网 在…

ubuntu22.04下YOLOv5 TensorRT模型部署

目录 Ubuntu22.04环境配置 1.1 安装工具链和opencv 1.2 安装Nvidia相关库 1.2.1 安装Nvidia显卡驱动 1.2.2 安装 cuda11.7 安装cuDNN 下载下载 tensorrt 下载仓库TensorRT-Alpha并设置 从yolov5源码中导出onnx文件 ​编辑 利用tensorrt编译onnx模型 编译执行yolov5-t…

spring 中的字节码文件访问 -- classreading 包

位于 spring-core 模块下的 org.springframework.core.type.classreading 包提供了读取类中元数据的功能。其实就是在不加载类的情况下,获取 class 文件中定义的类的相关信息:类名、接口、注解、方法及其注解、字段及其注解等。方便 spring 进行类型或指…

牛客0718B——Arraylist 和LinkedList static修饰变量和方法

目录 Q1:currentTimeMillis是什么? Q2:比较Arraylist 和LinkedList的查找时间 3、相关对比Vector和Arraylist 底层扩容的原理: Q4:static修饰静态代码块 修改1: 修改2: 修改3: 修改1: 修改2: Q5…

入坑树莓派(2)——树莓派4B与手机蓝牙通信

入坑树莓派(2)——树莓派4B与手机蓝牙通信 1、引言 在入坑树莓派(1)中已经搞掂了可视化问题。现在继续开展下一步,尝试与手机通信,一开始是想弄wifi连接的,但发现基于wifi的APP比较难弄,为了降低开发的难度,又因为树莓派板子自带蓝牙模块,所以直接选用蓝牙连接手机…

LabVIEW多串口通信

随着现代工业控制对数据采集和处理效率的要求不断提升,传统的单串口通信已无法满足多通道数据传输与大规模数据存取的需求。开发一种基于LabVIEW的多串口通信及数据存储系统,以提升数据处理速度和存储效率,保障生产线的稳定运行显得尤为重要。…

达梦+flowable改造

原项目springbootflowablemysql模式现需改造springbootflowable达梦&#xff0c; 1.在项目中引入达梦jpa包 引入高版本包已兼容flowable&#xff08;6.4.2&#xff09;liquibase&#xff08;3.6.2&#xff09; 我没有像网上做覆盖及达梦配置 <dependency> …

数据结构之树的存储结构详解与示例(C/C++)

文章目录 树的存储结构1. 顺序存储结构2. 链式存储结构结论 树&#xff08;Tree&#xff09;是一种非常常见的数据结构&#xff0c;它模拟了一种层级或分支结构。树由节点&#xff08;或称为顶点&#xff09;组成&#xff0c;每个节点包含一个值&#xff0c;并且可能有多个子节…

SpringDoc2问题汇总

在项目中尝试使用SpringDoc进行文档生成&#xff0c;在使用过程中遇到一系列的问题加以记录. 1.引入依赖 只是单纯的使用SpringDoc的话不需要引入一些乱七八糟的依赖&#xff0c;如今各种增强和拓展依赖层出不穷&#xff0c;但是随着这些依赖的出现带来的不仅是增强&#xff0…

在学习使用LabVIEW的过程中,需要注意哪些问题?

在学习使用LabVIEW的过程中&#xff0c;需要注意以下问题&#xff1a; 1. 基础知识 图形化编程思维&#xff1a; LabVIEW采用图形化编程方式&#xff0c;与传统的文本编程语言有很大不同&#xff0c;需要适应这种新的编程思维方式。数据流概念&#xff1a; 理解LabVIEW的核心数…

调用第三方接口-OkHttpClient

请求方式 POSTGET POST 单个新增 例如后端接口接收参数为 User user 使用OkHttpClient发送post请求 //封装body信息 JsonObject jsonObject new JsonObject(); jsonObject.put("userName","张三"); jsonObject.put("city","北京");…

服务器借助笔记本热点WIFI上网

一、同一局域网环境 1、当前环境&#xff0c;已有交换机组网环境&#xff0c;服务器已配置IP信息。 设备ip服务器125.10.100.12交换机125.10.100.0/24笔记本125.10.100.39 2、拓扑图 #mermaid-svg-D4moqMym9i0eeRBm {font-family:"trebuchet ms",verdana,arial,sa…

AFAC2024-基于保险条款的问答 比赛日记 llamafactory qwen npu 910B1

AFAC2024: 基于保险条款的问答挑战——我的实战日记 概述 在最近的AFAC2024竞赛中&#xff0c;我参与了基于保险条款的问答赛道。这是一次深度学习与自然语言处理的实战演练&#xff0c;旨在提升模型在复杂保险文本理解与问答生成方面的能力。本文将分享我的参赛过程&#xf…

Git技巧:如何重命名你的分支

0. 引言 本文将介绍如何在本地以及远程仓库中安全地重命名 Git 分支。 1. 在本地重命名分支 在本地重命名分支可以通过 git branch 命令完成&#xff0c;具体有两种方法&#xff1a; 方法1&#xff1a;当前分支重命名 如果你当前正在 old 分支上工作&#xff0c;想要将其重…

numpy的一些基本操作

文章目录 1.numpy数组的多种创建方式1.1使用np.array()创建1.2使用plt创建1.3使用np的routine函数创建 2.numpy的常用属性2.1shape2.2ndim2.3size2.4dtype 3.numpy的索引和切片3.1切出前两列数据3.2切出前两行数据3.3切出前两行的前两列的数据3.4数组数据翻转3.5练习&#xff1…

【权威发布】2024年生物技术与医学国际会议(IACBM 2024)

2024年生物技术与医学国际会议 2024 International Conference on Biotechnology and Medicine 【1】会议简介 2024年生物技术与医学国际会议旨在为全球生物技术与医学领域的专家学者提供一个交流最新研究成果、分享技术进展和探讨未来发展方向的平台。会议旨在加强国际间的学术…