prometheus_reporter.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. // 首先确定监测指标:度量什么(Name),
  2. // 再确定监测点
  3. package metrics
  4. import (
  5. "fmt"
  6. "log"
  7. "net/http"
  8. "sync"
  9. "leafstalk/conf"
  10. "github.com/prometheus/client_golang/prometheus"
  11. "github.com/prometheus/client_golang/prometheus/promhttp"
  12. )
  13. var (
  14. prometheusReporter *PrometheusReporter
  15. once sync.Once
  16. )
  17. // PrometheusReporter reports metrics to prometheus
  18. type PrometheusReporter struct {
  19. serverType string
  20. project string
  21. countReportersMap map[string]*prometheus.CounterVec
  22. summaryReportersMap map[string]*prometheus.SummaryVec
  23. gaugeReportersMap map[string]*prometheus.GaugeVec
  24. histogramReportersMap map[string]*prometheus.HistogramVec
  25. additionalLabels map[string]string
  26. }
  27. func (p *PrometheusReporter) registerCustomMetrics(
  28. constLabels map[string]string,
  29. additionalLabelsKeys []string,
  30. spec *CustomMetricsSpec,
  31. ) {
  32. // 监测点指定比例的分布情况
  33. for _, summary := range spec.Summaries {
  34. p.summaryReportersMap[summary.Name] = prometheus.NewSummaryVec(
  35. prometheus.SummaryOpts{
  36. Namespace: p.serverType,
  37. Subsystem: summary.Subsystem,
  38. Name: summary.Name,
  39. Help: summary.Help,
  40. Objectives: summary.Objectives,
  41. ConstLabels: constLabels,
  42. },
  43. append(additionalLabelsKeys, summary.Labels...),
  44. )
  45. }
  46. // 监测点数值变化度量,变大变小
  47. for _, gauge := range spec.Gauges {
  48. p.gaugeReportersMap[gauge.Name] = prometheus.NewGaugeVec(
  49. prometheus.GaugeOpts{
  50. Namespace: p.serverType,
  51. Subsystem: gauge.Subsystem,
  52. Name: gauge.Name,
  53. Help: gauge.Help,
  54. ConstLabels: constLabels,
  55. },
  56. append(additionalLabelsKeys, gauge.Labels...),
  57. )
  58. }
  59. // 监测点命中次数或
  60. for _, counter := range spec.Counters {
  61. p.countReportersMap[counter.Name] = prometheus.NewCounterVec(
  62. prometheus.CounterOpts{
  63. Namespace: p.serverType,
  64. Subsystem: counter.Subsystem,
  65. Name: counter.Name,
  66. Help: counter.Help,
  67. ConstLabels: constLabels,
  68. },
  69. append(additionalLabelsKeys, counter.Labels...),
  70. )
  71. }
  72. }
  73. func (p *PrometheusReporter) registerMetrics(
  74. constLabels, additionalLabels map[string]string,
  75. spec *CustomMetricsSpec,
  76. ) {
  77. // constLabels["game"] = p.game
  78. // constLabels["serverType"] = p.serverType
  79. p.additionalLabels = additionalLabels
  80. additionalLabelsKeys := make([]string, 0, len(additionalLabels))
  81. for key := range additionalLabels {
  82. additionalLabelsKeys = append(additionalLabelsKeys, key)
  83. }
  84. p.registerCustomMetrics(constLabels, additionalLabelsKeys, spec)
  85. // 定义多个指标,并选择响应的度量方式
  86. // HandlerResponseTimeMs summary
  87. // 响应耗时分布统计
  88. p.summaryReportersMap[ResponseTime] = prometheus.NewSummaryVec(
  89. prometheus.SummaryOpts{
  90. Namespace: p.serverType,
  91. Subsystem: "handler",
  92. Name: ResponseTime,
  93. Help: "处理一条消息耗时NS",
  94. Objectives: map[float64]float64{0.7: 0.02, 0.95: 0.005, 0.99: 0.001},
  95. ConstLabels: constLabels,
  96. },
  97. append([]string{"route", "status", "type", "code"}, additionalLabelsKeys...),
  98. )
  99. // ProcessDelay summary
  100. // 用户请求延时分布
  101. p.summaryReportersMap[ProcessDelay] = prometheus.NewSummaryVec(
  102. prometheus.SummaryOpts{
  103. Namespace: p.serverType,
  104. Subsystem: "handler",
  105. Name: ProcessDelay,
  106. Help: "处理消息延迟NS",
  107. Objectives: map[float64]float64{0.7: 0.02, 0.95: 0.005, 0.99: 0.001},
  108. ConstLabels: constLabels,
  109. },
  110. append([]string{"route", "type"}, additionalLabelsKeys...),
  111. )
  112. // ConnectedClients gauge
  113. // 当前的客户端连接数
  114. p.gaugeReportersMap[ConnectedClients] = prometheus.NewGaugeVec(
  115. prometheus.GaugeOpts{
  116. Namespace: p.serverType,
  117. Subsystem: "acceptor",
  118. Name: ConnectedClients,
  119. Help: "当前连接的客户端数目",
  120. ConstLabels: constLabels,
  121. },
  122. additionalLabelsKeys,
  123. )
  124. // 当前服务端连接数
  125. p.gaugeReportersMap[CountServers] = prometheus.NewGaugeVec(
  126. prometheus.GaugeOpts{
  127. Namespace: p.serverType,
  128. Subsystem: "service_cluster",
  129. Name: CountServers,
  130. Help: "当前连接的服务端数量",
  131. ConstLabels: constLabels,
  132. },
  133. append([]string{"type"}, additionalLabelsKeys...),
  134. )
  135. // 通道可用容量
  136. p.gaugeReportersMap[ChannelCapacity] = prometheus.NewGaugeVec(
  137. prometheus.GaugeOpts{
  138. Namespace: p.serverType,
  139. Subsystem: "channel",
  140. Name: ChannelCapacity,
  141. Help: "the available capacity of the channel",
  142. ConstLabels: constLabels,
  143. },
  144. append([]string{"channel"}, additionalLabelsKeys...),
  145. )
  146. // 丢弃RPC消息的数量
  147. p.gaugeReportersMap[DroppedMessages] = prometheus.NewGaugeVec(
  148. prometheus.GaugeOpts{
  149. Namespace: p.serverType,
  150. Subsystem: "rpc_server",
  151. Name: DroppedMessages,
  152. Help: "the number of rpc server dropped messages (messages that are not handled)",
  153. ConstLabels: constLabels,
  154. },
  155. additionalLabelsKeys,
  156. )
  157. // 当前协程数量
  158. p.gaugeReportersMap[Goroutines] = prometheus.NewGaugeVec(
  159. prometheus.GaugeOpts{
  160. Namespace: p.serverType,
  161. Subsystem: "sys",
  162. Name: Goroutines,
  163. Help: "当前协程数量",
  164. ConstLabels: constLabels,
  165. },
  166. additionalLabelsKeys,
  167. )
  168. // 当前堆大小
  169. p.gaugeReportersMap[HeapSize] = prometheus.NewGaugeVec(
  170. prometheus.GaugeOpts{
  171. Namespace: p.serverType,
  172. Subsystem: "sys",
  173. Name: HeapSize,
  174. Help: "当前堆的大小",
  175. ConstLabels: constLabels,
  176. },
  177. additionalLabelsKeys,
  178. )
  179. // 当前堆栈对象数目
  180. p.gaugeReportersMap[HeapObjects] = prometheus.NewGaugeVec(
  181. prometheus.GaugeOpts{
  182. Namespace: p.serverType,
  183. Subsystem: "sys",
  184. Name: HeapObjects,
  185. Help: "当前堆对象数目",
  186. ConstLabels: constLabels,
  187. },
  188. additionalLabelsKeys,
  189. )
  190. // 当前重试JOB数量
  191. p.gaugeReportersMap[WorkerJobsRetry] = prometheus.NewGaugeVec(
  192. prometheus.GaugeOpts{
  193. Namespace: p.serverType,
  194. Subsystem: "worker",
  195. Name: WorkerJobsRetry,
  196. Help: "当前重试JOB数量",
  197. ConstLabels: constLabels,
  198. },
  199. additionalLabelsKeys,
  200. )
  201. //当前队列大小
  202. p.gaugeReportersMap[WorkerQueueSize] = prometheus.NewGaugeVec(
  203. prometheus.GaugeOpts{
  204. Namespace: p.serverType,
  205. Subsystem: "worker",
  206. Name: WorkerQueueSize,
  207. Help: "当前队列大小",
  208. ConstLabels: constLabels,
  209. },
  210. append([]string{"queue"}, additionalLabelsKeys...),
  211. )
  212. //
  213. p.gaugeReportersMap[WorkerJobsTotal] = prometheus.NewGaugeVec(
  214. prometheus.GaugeOpts{
  215. Namespace: p.serverType,
  216. Subsystem: "worker",
  217. Name: WorkerJobsTotal,
  218. Help: "the total executed jobs",
  219. ConstLabels: constLabels,
  220. },
  221. append([]string{"status"}, additionalLabelsKeys...),
  222. )
  223. // 计数度量
  224. p.countReportersMap[ExceededRateLimiting] = prometheus.NewCounterVec(
  225. prometheus.CounterOpts{
  226. Namespace: p.serverType,
  227. Subsystem: "acceptor",
  228. Name: ExceededRateLimiting,
  229. Help: "the number of blocked requests by exceeded rate limiting",
  230. ConstLabels: constLabels,
  231. },
  232. additionalLabelsKeys,
  233. )
  234. // 玩家请求的消息计数
  235. p.countReportersMap[MessageHandler] = prometheus.NewCounterVec(
  236. prometheus.CounterOpts{
  237. Namespace: p.serverType,
  238. Subsystem: "messageHandler",
  239. Name: MessageHandler,
  240. Help: "玩家发送请求数量",
  241. ConstLabels: constLabels,
  242. },
  243. append([]string{"handler"}, additionalLabelsKeys...),
  244. )
  245. p.histogramReportersMap[MessageResponseTime] = prometheus.NewHistogramVec(
  246. prometheus.HistogramOpts{
  247. Namespace: p.serverType,
  248. Name: MessageResponseTime,
  249. Help: "各种消息响应耗时",
  250. },
  251. []string{"handler"},
  252. )
  253. // 注册到注册表
  254. toRegister := make([]prometheus.Collector, 0)
  255. for _, c := range p.countReportersMap {
  256. toRegister = append(toRegister, c)
  257. }
  258. for _, c := range p.gaugeReportersMap {
  259. toRegister = append(toRegister, c)
  260. }
  261. for _, c := range p.summaryReportersMap {
  262. toRegister = append(toRegister, c)
  263. }
  264. for _, c := range p.histogramReportersMap {
  265. toRegister = append(toRegister, c)
  266. }
  267. prometheus.MustRegister(toRegister...)
  268. }
  269. // StartPrometheusReporter gets the prometheus reporter singleton
  270. func StartPrometheusReporter(
  271. serverType string,
  272. config *conf.Config,
  273. // constLabels map[string]string,
  274. ) (*PrometheusReporter, error) {
  275. once.Do(func() {
  276. var (
  277. port = config.GetInt("metrics.prometheus.port")
  278. game = config.GetString("projectName")
  279. additionalLabels = config.GetStringMapString("metrics.additionalTags")
  280. constLabels = config.GetStringMapString("metrics.constTags")
  281. )
  282. prometheusReporter = &PrometheusReporter{
  283. serverType: serverType,
  284. project: game,
  285. countReportersMap: make(map[string]*prometheus.CounterVec),
  286. summaryReportersMap: make(map[string]*prometheus.SummaryVec),
  287. gaugeReportersMap: make(map[string]*prometheus.GaugeVec),
  288. histogramReportersMap: make(map[string]*prometheus.HistogramVec),
  289. }
  290. spec, err := NewCustomMetricsSpec(config)
  291. if err != nil {
  292. log.Fatalf("NewCustomMetricsSpec error. %v", err)
  293. return
  294. }
  295. prometheusReporter.registerMetrics(constLabels, additionalLabels, spec)
  296. http.Handle("/metrics", promhttp.Handler())
  297. go (func() {
  298. log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
  299. })()
  300. })
  301. return prometheusReporter, nil
  302. }
  303. // ReportSummary reports a summary metric
  304. func (p *PrometheusReporter) ReportSummary(metric string, labels map[string]string, value float64) error {
  305. sum := p.summaryReportersMap[metric]
  306. if sum != nil {
  307. labels = p.ensureLabels(labels)
  308. sum.With(labels).Observe(value)
  309. return nil
  310. }
  311. return ErrMetricNotKnown
  312. }
  313. // ReportCount reports a summary metric
  314. func (p *PrometheusReporter) ReportCount(metric string, labels map[string]string, count float64) error {
  315. cnt := p.countReportersMap[metric]
  316. if cnt != nil {
  317. labels = p.ensureLabels(labels)
  318. cnt.With(labels).Add(count)
  319. return nil
  320. }
  321. return ErrMetricNotKnown
  322. }
  323. // ReportGauge reports a gauge metric
  324. func (p *PrometheusReporter) ReportGauge(metric string, labels map[string]string, value float64) error {
  325. g := p.gaugeReportersMap[metric]
  326. if g != nil {
  327. labels = p.ensureLabels(labels)
  328. g.With(labels).Set(value)
  329. return nil
  330. }
  331. return ErrMetricNotKnown
  332. }
  333. // ReportHistogram reports a histogram metric
  334. func (p *PrometheusReporter) ReportHistogram(metric string, label string, value float64) error {
  335. g := p.histogramReportersMap[metric]
  336. if g != nil {
  337. g.WithLabelValues(label).Observe(value)
  338. return nil
  339. }
  340. return ErrMetricNotKnown
  341. }
  342. // ensureLabels checks if labels contains the additionalLabels values,
  343. // otherwise adds them with the default values
  344. func (p *PrometheusReporter) ensureLabels(labels map[string]string) map[string]string {
  345. for key, defaultVal := range p.additionalLabels {
  346. if _, ok := labels[key]; !ok {
  347. labels[key] = defaultVal
  348. }
  349. }
  350. return labels
  351. }