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  }