main.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. package main
  2. import (
  3. "context"
  4. "log/slog"
  5. "net/http"
  6. "os"
  7. "xugu_exporter/collector"
  8. _ "gitee.com/XuguDB/go-xugu-driver"
  9. kingpin "github.com/alecthomas/kingpin/v2"
  10. "github.com/go-kit/log/level"
  11. "github.com/prometheus/client_golang/prometheus"
  12. "github.com/prometheus/client_golang/prometheus/collectors"
  13. "github.com/prometheus/client_golang/prometheus/promhttp"
  14. "github.com/prometheus/common/promlog"
  15. "github.com/prometheus/common/promlog/flag"
  16. "github.com/prometheus/common/version"
  17. "github.com/prometheus/exporter-toolkit/web"
  18. webflag "github.com/prometheus/exporter-toolkit/web/kingpinflag"
  19. // Required for debugging
  20. // _ "net/http/pprof"
  21. )
  22. var (
  23. // Version will be set at build time.
  24. Version = "0.0.1.dev" // 版本号,通常在构建时设置。这里初始化为一个开发版本号。
  25. // 使用 Kingpin 库定义命令行标志,并为每个标志提供帮助信息和默认值。
  26. // metricPath 定义了暴露指标的路径。默认值来自环境变量 "TELEMETRY_PATH",若未设置则默认为 "/metrics"。
  27. metricPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics. (env: TELEMETRY_PATH)").Default(getEnv("TELEMETRY_PATH", "/metrics")).String()
  28. // dsn 定义了数据库的连接字符串。默认值来自环境变量 "DATA_SOURCE_NAME",若未设置则默认为空字符串。
  29. dsn = kingpin.Flag("database.dsn",
  30. "Connection string to a data source. (env: DATA_SOURCE_NAME)",
  31. ).Default(getEnv("DATA_SOURCE_NAME", "")).String()
  32. // dsnFile 定义了从文件读取数据库连接字符串的路径。默认值来自环境变量 "DATA_SOURCE_NAME_FILE",若未设置则默认为空字符串。
  33. dsnFile = kingpin.Flag("database.dsnFile",
  34. "File to read a string to a data source from. (env: DATA_SOURCE_NAME_FILE)",
  35. ).Default(getEnv("DATA_SOURCE_NAME_FILE", "")).String()
  36. // defaultFileMetrics 定义了存储默认指标的文件路径。该文件支持 TOML 或 YAML 格式。默认值来自环境变量 "DEFAULT_METRICS",若未设置则默认为 "default-metrics.toml"。
  37. defaultFileMetrics = kingpin.Flag(
  38. "default.metrics",
  39. "File with default metrics in a toml format. (env: DEFAULT_METRICS)",
  40. ).Default(getEnv("DEFAULT_METRICS", "default-metrics.toml")).String()
  41. // customMetrics 定义了包含自定义指标的文件路径。该文件支持 TOML 或 YAML 格式。默认值来自环境变量 "CUSTOM_METRICS",若未设置则默认为空字符串。
  42. customMetrics = kingpin.Flag(
  43. "custom.metrics",
  44. "File that may contain various custom metrics in a toml format. (env: CUSTOM_METRICS)",
  45. ).Default(getEnv("CUSTOM_METRICS", "")).String()
  46. // queryTimeout 定义了查询的超时时间,单位为秒。默认值来自环境变量 "QUERY_TIMEOUT",若未设置则默认为 5 秒。
  47. queryTimeout = kingpin.Flag(
  48. "query.timeout",
  49. "Query timeout (in seconds). (env: QUERY_TIMEOUT)",
  50. ).Default(getEnv("QUERY_TIMEOUT", "5")).Int()
  51. // maxIdleConns 定义了连接池中最大空闲连接数。默认值来自环境变量 "DATABASE_MAXIDLECONNS",若未设置则默认为 0。
  52. maxIdleConns = kingpin.Flag(
  53. "database.maxIdleConns",
  54. "Number of maximum idle connections in the connection pool. (env: DATABASE_MAXIDLECONNS)",
  55. ).Default(getEnv("DATABASE_MAXIDLECONNS", "0")).Int()
  56. // maxOpenConns 定义了连接池中最大打开连接数。默认值来自环境变量 "DATABASE_MAXOPENCONNS",若未设置则默认为 10。
  57. maxOpenConns = kingpin.Flag(
  58. "database.maxOpenConns",
  59. "Number of maximum open connections in the connection pool. (env: DATABASE_MAXOPENCONNS)",
  60. ).Default(getEnv("DATABASE_MAXOPENCONNS", "10")).Int()
  61. // scrapeInterval 定义了每次抓取数据的间隔时间。默认值为 0,表示在每次收集请求时进行抓取。
  62. scrapeInterval = kingpin.Flag(
  63. "scrape.interval",
  64. "Interval between each scrape. Default is to scrape on collect requests",
  65. ).Default("0s").Duration()
  66. // toolkitFlags 是与 Web 相关的附加标志,添加到 `kingpin.CommandLine` 上,默认端口为 ":9161"。
  67. toolkitFlags = webflag.AddFlags(kingpin.CommandLine, ":9161")
  68. )
  69. func main() {
  70. // 创建 Prometheus 日志配置对象
  71. promLogConfig := &promlog.Config{}
  72. // 添加命令行标志以配置 Prometheus 日志
  73. flag.AddFlags(kingpin.CommandLine, promLogConfig)
  74. // 设置帮助标志的快捷键
  75. kingpin.HelpFlag.Short('\n')
  76. // 设置程序版本信息
  77. kingpin.Version(version.Print("xugudb_exporter"))
  78. // 解析命令行输入的参数
  79. kingpin.Parse()
  80. // 创建新的日志记录器
  81. logger := promlog.New(promLogConfig)
  82. // 如果提供了 dsnFile 参数,读取文件中的数据库连接信息
  83. if dsnFile != nil && *dsnFile != "" {
  84. dsnFileContent, err := os.ReadFile(*dsnFile)
  85. if err != nil {
  86. // 如果文件读取失败,记录错误并退出程序
  87. level.Error(logger).Log("msg", "Unable to read DATA_SOURCE_NAME_FILE", "file", dsnFile, "error", err)
  88. os.Exit(1)
  89. }
  90. // 将文件内容作为数据库连接字符串
  91. *dsn = string(dsnFileContent)
  92. }
  93. // 初始化配置对象,将从命令行解析的参数赋值给配置
  94. config := &collector.Config{
  95. DSN: *dsn, // 数据库连接字符串
  96. MaxOpenConns: *maxOpenConns, // 最大打开连接数
  97. MaxIdleConns: *maxIdleConns, // 最大空闲连接数
  98. CustomMetrics: *customMetrics, // 自定义指标文件路径
  99. QueryTimeout: *queryTimeout, // 查询超时时间
  100. DefaultMetricsFile: *defaultFileMetrics, // 默认指标文件路径
  101. }
  102. // 创建一个新的 Exporter 实例,用于收集 xugu 数据库的指标
  103. exporter, err := collector.NewExporter(logger, config)
  104. if err != nil {
  105. // 如果创建 Exporter 失败,记录错误并退出程序
  106. level.Error(logger).Log("unable to connect to DB", err)
  107. }
  108. // 如果设置了抓取间隔(scrapeInterval),则启动定时抓取指标的任务
  109. if *scrapeInterval != 0 {
  110. ctx, cancel := context.WithCancel(context.Background())
  111. defer cancel()
  112. // 启动一个 goroutine,定期从数据库抓取指标
  113. go exporter.RunScheduledScrapes(ctx, *scrapeInterval)
  114. }
  115. // 将 Exporter 注册到 Prometheus 中,供 Prometheus 进行指标抓取
  116. prometheus.MustRegister(exporter)
  117. // 注册构建信息收集器,用于报告程序的版本信息等元数据
  118. prometheus.MustRegister(collectors.NewBuildInfoCollector())
  119. // 记录启动信息
  120. level.Info(logger).Log("msg", "Starting xugudb_exporter", "version", version.Info())
  121. level.Info(logger).Log("msg", "Build context", "build", version.BuildContext())
  122. level.Info(logger).Log("msg", "Collect from: ", "metricPath", *metricPath)
  123. // 设置 Prometheus HTTP handler 的选项
  124. opts := promhttp.HandlerOpts{
  125. ErrorHandling: promhttp.ContinueOnError, // 遇到错误时继续处理其他请求
  126. }
  127. // 配置 /metrics 路径用于暴露 Prometheus 格式的指标
  128. http.Handle(*metricPath, promhttp.HandlerFor(prometheus.DefaultGatherer, opts))
  129. // 配置根路径(/),返回一个简单的 HTML 页面,包含版本信息和指标链接
  130. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  131. w.Write([]byte("<html><head><title>xugu DB Exporter " + Version + "</title></head><body><h1>xugu DB Exporter " + Version + "</h1><p><a href='" + *metricPath + "'>Metrics</a></p></body></html>"))
  132. })
  133. // 创建一个日志处理器,输出到标准输出(os.Stdout)
  134. handlerS := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
  135. Level: slog.LevelInfo, // 设置最低日志级别为 Info
  136. })
  137. // 创建一个新的 logger
  138. loggerS := slog.New(handlerS)
  139. // 创建一个新的 logger
  140. //loggerS := slog.New(slog.NewTextHandler(slog.Default()))
  141. // 使用 logger 记录日志
  142. loggerS.Info("This is an info message")
  143. loggerS.Warn("This is a warning message")
  144. loggerS.Error("This is an error message")
  145. // 如果需要,可以添加更多的上下文信息
  146. loggerS.With("context", "example").Info("This is a context-aware info message")
  147. // 创建一个 HTTP 服务器实例
  148. server := &http.Server{}
  149. // 启动 HTTP 服务器,监听并提供 Prometheus 指标
  150. if err := web.ListenAndServe(server, toolkitFlags, loggerS); err != nil {
  151. // 如果服务器启动失败,记录错误并退出程序
  152. level.Error(logger).Log("msg", "Listening error", "reason", err)
  153. os.Exit(1)
  154. }
  155. }
  156. // getEnv 返回指定环境变量的值,如果环境变量未设置,则返回提供的备用值。
  157. func getEnv(key, fallback string) string {
  158. // os.LookupEnv 用于查找环境变量的值。如果环境变量存在,返回值和一个布尔值(true/false);
  159. // 如果环境变量不存在,返回空字符串和 false。
  160. if value, ok := os.LookupEnv(key); ok {
  161. // 如果环境变量存在,返回其值
  162. return value
  163. }
  164. // 如果环境变量不存在,返回备用值
  165. return fallback
  166. }