github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/pkg/promutil/util.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package promutil 15 16 import ( 17 "net/http" 18 19 frameModel "github.com/pingcap/tiflow/engine/framework/model" 20 engineModel "github.com/pingcap/tiflow/engine/model" 21 "github.com/pingcap/tiflow/engine/pkg/tenant" 22 "github.com/prometheus/client_golang/prometheus" 23 ) 24 25 // Routine to get a Factory: 26 // 1. Servermaster/Executor maintains a process-level prometheus.Registerer singleton. 27 // 2. 'BaseMaster/BaseWorker' interface offers a method 'func PromFactory() Factory'. 28 // 3. When app implements 'MasterImpl/WorkerImpl', it can get a Factory object by BaseWorker.PromFactory(). 29 // Actually, the return Factory object would be the wrappingFactory which can produce prometheus metric object 30 // with tenant and task information of dataflow engine. 31 // 4. App uses Factory.NewCounter(xxx) to produce the native prometheus object without any concern about the 32 // registration and http handler. Similar to usage of promauto. 33 34 const ( 35 systemID = "dataflow-system" 36 frameworkID = "dateflow-framework" 37 frameworkMetricPrefix = "dataflow" // avoid metric conflict with app 38 ) 39 40 const ( 41 /// framework const lable 42 constLabelFrameworkKey = "framework" 43 44 /// app const label 45 // constLabelTenantKey and constLabelProjectKey is used to recognize metric for tenant/project 46 constLabelTenantKey = "tenant" 47 constLabelProjectKey = "project_id" 48 // constLabelJobKey is used to recognize jobs of the same job type 49 constLabelJobKey = "job_id" 50 // constLabelWorkerKey is used to recognize workers of the same job 51 constLabelWorkerKey = "worker_id" 52 53 // test const lable 54 constLableTestKey = "test_id" 55 ) 56 57 // HTTPHandlerForMetric return http.Handler for prometheus metric 58 func HTTPHandlerForMetric() http.Handler { 59 return HTTPHandlerForMetricImpl(globalMetricGatherer) 60 } 61 62 // Metric produced by WrappingFactory has some inner const labels attached to it. 63 // 1. tenant const-labels: {tenant="xxx", project_id="xxx"} 64 // to distinguish different tenant/project metric 65 // 2. task const-labels: {job_id="xxx"} {worker_id="xxx"} 66 // app job master metric only has `job_id` label, app worker has all. 67 // (a) `job_id` can distinguish different tasks of the same job type 68 // (b) `worker_id` can distinguish different worker of the same job 69 // e.g. 70 // For JobMaster: 71 // {tenant="user0", project_id="debug", job_id="job0", xxx="xxx"(user defined const labels)} 72 // For Worker: 73 // {tenant="user0", project_id="debug", job_id="job0", worker_id="worker0", 74 // xxx="xxx"(user defined labels)} 75 // For Framework: 76 // {framework="true"} 77 // 78 // Besides, some specific prefix will be added to metric name to avoid 79 // cross app metric conflict. 80 // Currently, we will add `job_type` to the metric name. 81 // e.g. $Namespace_$Subsystem_$Name(original) ---> 82 // $JobType_$Namespace_$Subsystem_$Name(actual) 83 84 // NewFactory4Master return a Factory for jobmaster 85 func NewFactory4Master(info tenant.ProjectInfo, jobType engineModel.JobType, jobID engineModel.JobID) Factory { 86 // Only for the jobmanager 87 if jobType == engineModel.JobTypeJobManager { 88 return NewFactory4Framework() 89 } 90 91 // TODO: If the job type prefix is not required in metrics, change implementation 92 // of NewFactory4MasterImpl. 93 return NewFactory4MasterImpl(globalMetricRegistry, info, "", jobID) 94 } 95 96 // NewFactory4Worker return a Factory for worker 97 func NewFactory4Worker(info tenant.ProjectInfo, jobType engineModel.JobType, jobID engineModel.JobID, 98 workerID frameModel.WorkerID, 99 ) Factory { 100 // TODO: If the job type prefix is not required in metrics, change implementation 101 // of NewFactory4WorkerImpl. 102 return NewFactory4WorkerImpl(globalMetricRegistry, info, "", jobID, workerID) 103 } 104 105 // NewFactory4Test return a Factory for test 106 // NOTICE: we use testing.T.TempDir() to distinguish different test 107 func NewFactory4Test(testKey string) Factory { 108 return NewFactory4TestImpl(globalMetricRegistry, testKey) 109 } 110 111 // NewFactory4Framework return a Factory for dataflow framework 112 // NOTICE: we use auto service label tagged by cloud service to distinguish 113 // different dataflow engine or different executor 114 func NewFactory4Framework() Factory { 115 return NewFactory4FrameworkImpl(globalMetricRegistry) 116 } 117 118 // UnregisterWorkerMetrics unregisters all metrics of workerID 119 // IF 'worker' is a job master, use job id as workerID 120 // IF 'worker' is a worker, use worker id as workerID 121 func UnregisterWorkerMetrics(workerID frameModel.WorkerID) { 122 globalMetricRegistry.Unregister(workerID) 123 } 124 125 // GetGlobalMetricRegistry returns the global metric registry where auto-registering metrics are registered. 126 // The register to it should be only be done by its derived factories from NewFactory4Master, ... 127 // And the returned registry can be only used for unregister. 128 func GetGlobalMetricRegistry() prometheus.Registerer { 129 return NewOnlyUnregRegister(globalMetricRegistry.registry) 130 }