github.com/prebid/prebid-server/v2@v2.18.0/metrics/go_metrics.go (about)

     1  package metrics
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/golang/glog"
    10  	"github.com/prebid/prebid-server/v2/config"
    11  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    12  	metrics "github.com/rcrowley/go-metrics"
    13  )
    14  
    15  type Metrics struct {
    16  	MetricsRegistry                metrics.Registry
    17  	ConnectionCounter              metrics.Counter
    18  	TMaxTimeoutCounter             metrics.Counter
    19  	ConnectionAcceptErrorMeter     metrics.Meter
    20  	ConnectionCloseErrorMeter      metrics.Meter
    21  	ImpMeter                       metrics.Meter
    22  	AppRequestMeter                metrics.Meter
    23  	NoCookieMeter                  metrics.Meter
    24  	DebugRequestMeter              metrics.Meter
    25  	RequestTimer                   metrics.Timer
    26  	RequestsQueueTimer             map[RequestType]map[bool]metrics.Timer
    27  	PrebidCacheRequestTimerSuccess metrics.Timer
    28  	PrebidCacheRequestTimerError   metrics.Timer
    29  	StoredDataFetchTimer           map[StoredDataType]map[StoredDataFetchType]metrics.Timer
    30  	StoredDataErrorMeter           map[StoredDataType]map[StoredDataError]metrics.Meter
    31  	StoredReqCacheMeter            map[CacheResult]metrics.Meter
    32  	StoredImpCacheMeter            map[CacheResult]metrics.Meter
    33  	AccountCacheMeter              map[CacheResult]metrics.Meter
    34  	DNSLookupTimer                 metrics.Timer
    35  	TLSHandshakeTimer              metrics.Timer
    36  	BidderServerResponseTimer      metrics.Timer
    37  	StoredResponsesMeter           metrics.Meter
    38  
    39  	// Metrics for OpenRTB requests specifically
    40  	RequestStatuses       map[RequestType]map[RequestStatus]metrics.Meter
    41  	AmpNoCookieMeter      metrics.Meter
    42  	CookieSyncMeter       metrics.Meter
    43  	CookieSyncStatusMeter map[CookieSyncStatus]metrics.Meter
    44  	SyncerRequestsMeter   map[string]map[SyncerCookieSyncStatus]metrics.Meter
    45  	SetUidMeter           metrics.Meter
    46  	SetUidStatusMeter     map[SetUidStatus]metrics.Meter
    47  	SyncerSetsMeter       map[string]map[SyncerSetUidStatus]metrics.Meter
    48  
    49  	// Media types found in the "imp" JSON object
    50  	ImpsTypeBanner metrics.Meter
    51  	ImpsTypeVideo  metrics.Meter
    52  	ImpsTypeAudio  metrics.Meter
    53  	ImpsTypeNative metrics.Meter
    54  
    55  	// Notification timeout metrics
    56  	TimeoutNotificationSuccess metrics.Meter
    57  	TimeoutNotificationFailure metrics.Meter
    58  
    59  	// TCF adaption metrics
    60  	PrivacyCCPARequest       metrics.Meter
    61  	PrivacyCCPARequestOptOut metrics.Meter
    62  	PrivacyCOPPARequest      metrics.Meter
    63  	PrivacyLMTRequest        metrics.Meter
    64  	PrivacyTCFRequestVersion map[TCFVersionValue]metrics.Meter
    65  
    66  	AdapterMetrics map[string]*AdapterMetrics
    67  	// Don't export accountMetrics because we need helper functions here to insure its properly populated dynamically
    68  	accountMetrics        map[string]*accountMetrics
    69  	accountMetricsRWMutex sync.RWMutex
    70  
    71  	// adapter name exchanges
    72  	exchanges []string
    73  	modules   []string
    74  	// Will hold boolean values to help us disable metric collection if needed
    75  	MetricsDisabled config.DisabledMetrics
    76  
    77  	// AdsCert metrics
    78  	AdsCertRequestsSuccess metrics.Meter
    79  	AdsCertRequestsFailure metrics.Meter
    80  	adsCertSignTimer       metrics.Timer
    81  
    82  	// Module metrics
    83  	ModuleMetrics map[string]map[string]*ModuleMetrics
    84  
    85  	OverheadTimer map[OverheadType]metrics.Timer
    86  }
    87  
    88  // AdapterMetrics houses the metrics for a particular adapter
    89  type AdapterMetrics struct {
    90  	NoCookieMeter      metrics.Meter
    91  	ErrorMeters        map[AdapterError]metrics.Meter
    92  	NoBidMeter         metrics.Meter
    93  	GotBidsMeter       metrics.Meter
    94  	RequestTimer       metrics.Timer
    95  	PriceHistogram     metrics.Histogram
    96  	BidsReceivedMeter  metrics.Meter
    97  	PanicMeter         metrics.Meter
    98  	MarkupMetrics      map[openrtb_ext.BidType]*MarkupDeliveryMetrics
    99  	ConnCreated        metrics.Counter
   100  	ConnReused         metrics.Counter
   101  	ConnWaitTime       metrics.Timer
   102  	BuyerUIDScrubbed   metrics.Meter
   103  	GDPRRequestBlocked metrics.Meter
   104  
   105  	BidValidationCreativeSizeErrorMeter metrics.Meter
   106  	BidValidationCreativeSizeWarnMeter  metrics.Meter
   107  
   108  	BidValidationSecureMarkupErrorMeter metrics.Meter
   109  	BidValidationSecureMarkupWarnMeter  metrics.Meter
   110  }
   111  
   112  type MarkupDeliveryMetrics struct {
   113  	AdmMeter  metrics.Meter
   114  	NurlMeter metrics.Meter
   115  }
   116  
   117  type accountMetrics struct {
   118  	requestMeter      metrics.Meter
   119  	debugRequestMeter metrics.Meter
   120  	bidsReceivedMeter metrics.Meter
   121  	priceHistogram    metrics.Histogram
   122  	// store account by adapter metrics. Type is map[PBSBidder.BidderCode]
   123  	adapterMetrics       map[string]*AdapterMetrics
   124  	moduleMetrics        map[string]*ModuleMetrics
   125  	storedResponsesMeter metrics.Meter
   126  
   127  	bidValidationCreativeSizeMeter     metrics.Meter
   128  	bidValidationCreativeSizeWarnMeter metrics.Meter
   129  	bidValidationSecureMarkupMeter     metrics.Meter
   130  	bidValidationSecureMarkupWarnMeter metrics.Meter
   131  }
   132  
   133  type ModuleMetrics struct {
   134  	DurationTimer         metrics.Timer
   135  	CallCounter           metrics.Counter
   136  	FailureCounter        metrics.Counter
   137  	SuccessNoopCounter    metrics.Counter
   138  	SuccessUpdateCounter  metrics.Counter
   139  	SuccessRejectCounter  metrics.Counter
   140  	ExecutionErrorCounter metrics.Counter
   141  	TimeoutCounter        metrics.Counter
   142  }
   143  
   144  // NewBlankMetrics creates a new Metrics object with all blank metrics object. This may also be useful for
   145  // testing routines to ensure that no metrics are written anywhere.
   146  //
   147  // This will be useful when removing endpoints, we can just run will the blank metrics function
   148  // rather than loading metrics that never get filled.
   149  // This will also eventually let us configure metrics, such as setting a limited set of metrics
   150  // for a production instance, and then expanding again when we need more debugging.
   151  func NewBlankMetrics(registry metrics.Registry, exchanges []string, disabledMetrics config.DisabledMetrics, moduleStageNames map[string][]string) *Metrics {
   152  	blankMeter := &metrics.NilMeter{}
   153  	blankTimer := &metrics.NilTimer{}
   154  
   155  	newMetrics := &Metrics{
   156  		MetricsRegistry:                registry,
   157  		RequestStatuses:                make(map[RequestType]map[RequestStatus]metrics.Meter),
   158  		ConnectionCounter:              metrics.NilCounter{},
   159  		ConnectionAcceptErrorMeter:     blankMeter,
   160  		ConnectionCloseErrorMeter:      blankMeter,
   161  		ImpMeter:                       blankMeter,
   162  		AppRequestMeter:                blankMeter,
   163  		DebugRequestMeter:              blankMeter,
   164  		NoCookieMeter:                  blankMeter,
   165  		RequestTimer:                   blankTimer,
   166  		DNSLookupTimer:                 blankTimer,
   167  		TLSHandshakeTimer:              blankTimer,
   168  		RequestsQueueTimer:             make(map[RequestType]map[bool]metrics.Timer),
   169  		PrebidCacheRequestTimerSuccess: blankTimer,
   170  		PrebidCacheRequestTimerError:   blankTimer,
   171  		StoredDataFetchTimer:           make(map[StoredDataType]map[StoredDataFetchType]metrics.Timer),
   172  		StoredDataErrorMeter:           make(map[StoredDataType]map[StoredDataError]metrics.Meter),
   173  		StoredReqCacheMeter:            make(map[CacheResult]metrics.Meter),
   174  		StoredImpCacheMeter:            make(map[CacheResult]metrics.Meter),
   175  		AccountCacheMeter:              make(map[CacheResult]metrics.Meter),
   176  		AmpNoCookieMeter:               blankMeter,
   177  		CookieSyncMeter:                blankMeter,
   178  		CookieSyncStatusMeter:          make(map[CookieSyncStatus]metrics.Meter),
   179  		SyncerRequestsMeter:            make(map[string]map[SyncerCookieSyncStatus]metrics.Meter),
   180  		SetUidMeter:                    blankMeter,
   181  		SetUidStatusMeter:              make(map[SetUidStatus]metrics.Meter),
   182  		SyncerSetsMeter:                make(map[string]map[SyncerSetUidStatus]metrics.Meter),
   183  		StoredResponsesMeter:           blankMeter,
   184  
   185  		ImpsTypeBanner: blankMeter,
   186  		ImpsTypeVideo:  blankMeter,
   187  		ImpsTypeAudio:  blankMeter,
   188  		ImpsTypeNative: blankMeter,
   189  
   190  		TimeoutNotificationSuccess: blankMeter,
   191  		TimeoutNotificationFailure: blankMeter,
   192  
   193  		PrivacyCCPARequest:       blankMeter,
   194  		PrivacyCCPARequestOptOut: blankMeter,
   195  		PrivacyCOPPARequest:      blankMeter,
   196  		PrivacyLMTRequest:        blankMeter,
   197  		PrivacyTCFRequestVersion: make(map[TCFVersionValue]metrics.Meter, len(TCFVersions())),
   198  
   199  		AdapterMetrics:  make(map[string]*AdapterMetrics, len(exchanges)),
   200  		accountMetrics:  make(map[string]*accountMetrics),
   201  		MetricsDisabled: disabledMetrics,
   202  
   203  		AdsCertRequestsSuccess: blankMeter,
   204  		AdsCertRequestsFailure: blankMeter,
   205  		adsCertSignTimer:       blankTimer,
   206  
   207  		ModuleMetrics: make(map[string]map[string]*ModuleMetrics),
   208  
   209  		exchanges: exchanges,
   210  		modules:   getModuleNames(moduleStageNames),
   211  
   212  		OverheadTimer:             makeBlankOverheadTimerMetrics(),
   213  		BidderServerResponseTimer: blankTimer,
   214  	}
   215  
   216  	for _, a := range exchanges {
   217  		newMetrics.AdapterMetrics[a] = makeBlankAdapterMetrics(newMetrics.MetricsDisabled)
   218  	}
   219  
   220  	for module, stages := range moduleStageNames {
   221  		newMetrics.ModuleMetrics[module] = makeBlankModuleStageMetrics(stages)
   222  	}
   223  
   224  	for _, t := range RequestTypes() {
   225  		newMetrics.RequestStatuses[t] = make(map[RequestStatus]metrics.Meter)
   226  		for _, s := range RequestStatuses() {
   227  			newMetrics.RequestStatuses[t][s] = blankMeter
   228  		}
   229  	}
   230  
   231  	for _, c := range CacheResults() {
   232  		newMetrics.StoredReqCacheMeter[c] = blankMeter
   233  		newMetrics.StoredImpCacheMeter[c] = blankMeter
   234  		newMetrics.AccountCacheMeter[c] = blankMeter
   235  	}
   236  
   237  	for _, v := range TCFVersions() {
   238  		newMetrics.PrivacyTCFRequestVersion[v] = blankMeter
   239  	}
   240  
   241  	for _, dt := range StoredDataTypes() {
   242  		newMetrics.StoredDataFetchTimer[dt] = make(map[StoredDataFetchType]metrics.Timer)
   243  		newMetrics.StoredDataErrorMeter[dt] = make(map[StoredDataError]metrics.Meter)
   244  		for _, ft := range StoredDataFetchTypes() {
   245  			newMetrics.StoredDataFetchTimer[dt][ft] = blankTimer
   246  		}
   247  		for _, e := range StoredDataErrors() {
   248  			newMetrics.StoredDataErrorMeter[dt][e] = blankMeter
   249  		}
   250  	}
   251  
   252  	//to minimize memory usage, queuedTimeout metric is now supported for video endpoint only
   253  	//boolean value represents 2 general request statuses: accepted and rejected
   254  	newMetrics.RequestsQueueTimer["video"] = make(map[bool]metrics.Timer)
   255  	newMetrics.RequestsQueueTimer["video"][true] = blankTimer
   256  	newMetrics.RequestsQueueTimer["video"][false] = blankTimer
   257  	return newMetrics
   258  }
   259  
   260  func getModuleNames(moduleStageNames map[string][]string) []string {
   261  	names := make([]string, len(moduleStageNames))
   262  
   263  	i := 0
   264  	for moduleName := range moduleStageNames {
   265  		names[i] = moduleName
   266  		i++
   267  	}
   268  
   269  	return names
   270  }
   271  
   272  // NewMetrics creates a new Metrics object with needed metrics defined. In time we may develop to the point
   273  // where Metrics contains all the metrics we might want to record, and then we build the actual
   274  // metrics object to contain only the metrics we are interested in. This would allow for debug
   275  // mode metrics. The code would allways try to record the metrics, but effectively noop if we are
   276  // using a blank meter/timer.
   277  func NewMetrics(registry metrics.Registry, exchanges []openrtb_ext.BidderName, disableAccountMetrics config.DisabledMetrics, syncerKeys []string, moduleStageNames map[string][]string) *Metrics {
   278  	lowerCaseExchanges := []string{}
   279  	for _, exchange := range exchanges {
   280  		lowerCaseExchanges = append(lowerCaseExchanges, strings.ToLower(string(exchange)))
   281  	}
   282  	newMetrics := NewBlankMetrics(registry, lowerCaseExchanges, disableAccountMetrics, moduleStageNames)
   283  	newMetrics.ConnectionCounter = metrics.GetOrRegisterCounter("active_connections", registry)
   284  	newMetrics.TMaxTimeoutCounter = metrics.GetOrRegisterCounter("tmax_timeout", registry)
   285  	newMetrics.ConnectionAcceptErrorMeter = metrics.GetOrRegisterMeter("connection_accept_errors", registry)
   286  	newMetrics.ConnectionCloseErrorMeter = metrics.GetOrRegisterMeter("connection_close_errors", registry)
   287  	newMetrics.ImpMeter = metrics.GetOrRegisterMeter("imps_requested", registry)
   288  
   289  	newMetrics.ImpsTypeBanner = metrics.GetOrRegisterMeter("imp_banner", registry)
   290  	newMetrics.ImpsTypeVideo = metrics.GetOrRegisterMeter("imp_video", registry)
   291  	newMetrics.ImpsTypeAudio = metrics.GetOrRegisterMeter("imp_audio", registry)
   292  	newMetrics.ImpsTypeNative = metrics.GetOrRegisterMeter("imp_native", registry)
   293  
   294  	newMetrics.NoCookieMeter = metrics.GetOrRegisterMeter("no_cookie_requests", registry)
   295  	newMetrics.AppRequestMeter = metrics.GetOrRegisterMeter("app_requests", registry)
   296  	newMetrics.DebugRequestMeter = metrics.GetOrRegisterMeter("debug_requests", registry)
   297  	newMetrics.RequestTimer = metrics.GetOrRegisterTimer("request_time", registry)
   298  	newMetrics.DNSLookupTimer = metrics.GetOrRegisterTimer("dns_lookup_time", registry)
   299  	newMetrics.TLSHandshakeTimer = metrics.GetOrRegisterTimer("tls_handshake_time", registry)
   300  	newMetrics.PrebidCacheRequestTimerSuccess = metrics.GetOrRegisterTimer("prebid_cache_request_time.ok", registry)
   301  	newMetrics.PrebidCacheRequestTimerError = metrics.GetOrRegisterTimer("prebid_cache_request_time.err", registry)
   302  	newMetrics.StoredResponsesMeter = metrics.GetOrRegisterMeter("stored_responses", registry)
   303  	newMetrics.OverheadTimer = makeOverheadTimerMetrics(registry)
   304  	newMetrics.BidderServerResponseTimer = metrics.GetOrRegisterTimer("bidder_server_response_time_seconds", registry)
   305  
   306  	for _, dt := range StoredDataTypes() {
   307  		for _, ft := range StoredDataFetchTypes() {
   308  			timerName := fmt.Sprintf("stored_%s_fetch_time.%s", string(dt), string(ft))
   309  			newMetrics.StoredDataFetchTimer[dt][ft] = metrics.GetOrRegisterTimer(timerName, registry)
   310  		}
   311  		for _, e := range StoredDataErrors() {
   312  			meterName := fmt.Sprintf("stored_%s_error.%s", string(dt), string(e))
   313  			newMetrics.StoredDataErrorMeter[dt][e] = metrics.GetOrRegisterMeter(meterName, registry)
   314  		}
   315  	}
   316  
   317  	newMetrics.AmpNoCookieMeter = metrics.GetOrRegisterMeter("amp_no_cookie_requests", registry)
   318  
   319  	newMetrics.CookieSyncMeter = metrics.GetOrRegisterMeter("cookie_sync_requests", registry)
   320  	for _, s := range CookieSyncStatuses() {
   321  		newMetrics.CookieSyncStatusMeter[s] = metrics.GetOrRegisterMeter(fmt.Sprintf("cookie_sync_requests.%s", s), registry)
   322  	}
   323  
   324  	newMetrics.SetUidMeter = metrics.GetOrRegisterMeter("setuid_requests", registry)
   325  	for _, s := range SetUidStatuses() {
   326  		newMetrics.SetUidStatusMeter[s] = metrics.GetOrRegisterMeter(fmt.Sprintf("setuid_requests.%s", s), registry)
   327  	}
   328  
   329  	for _, syncerKey := range syncerKeys {
   330  		newMetrics.SyncerRequestsMeter[syncerKey] = make(map[SyncerCookieSyncStatus]metrics.Meter)
   331  		for _, status := range SyncerRequestStatuses() {
   332  			newMetrics.SyncerRequestsMeter[syncerKey][status] = metrics.GetOrRegisterMeter(fmt.Sprintf("syncer.%s.request.%s", syncerKey, status), registry)
   333  		}
   334  
   335  		newMetrics.SyncerSetsMeter[syncerKey] = make(map[SyncerSetUidStatus]metrics.Meter)
   336  		for _, status := range SyncerSetUidStatuses() {
   337  			newMetrics.SyncerSetsMeter[syncerKey][status] = metrics.GetOrRegisterMeter(fmt.Sprintf("syncer.%s.set.%s", syncerKey, status), registry)
   338  		}
   339  	}
   340  
   341  	for _, a := range lowerCaseExchanges {
   342  		registerAdapterMetrics(registry, "adapter", string(a), newMetrics.AdapterMetrics[a])
   343  	}
   344  
   345  	for typ, statusMap := range newMetrics.RequestStatuses {
   346  		for stat := range statusMap {
   347  			statusMap[stat] = metrics.GetOrRegisterMeter("requests."+string(stat)+"."+string(typ), registry)
   348  		}
   349  	}
   350  
   351  	for _, cacheRes := range CacheResults() {
   352  		newMetrics.StoredReqCacheMeter[cacheRes] = metrics.GetOrRegisterMeter(fmt.Sprintf("stored_request_cache_%s", string(cacheRes)), registry)
   353  		newMetrics.StoredImpCacheMeter[cacheRes] = metrics.GetOrRegisterMeter(fmt.Sprintf("stored_imp_cache_%s", string(cacheRes)), registry)
   354  		newMetrics.AccountCacheMeter[cacheRes] = metrics.GetOrRegisterMeter(fmt.Sprintf("account_cache_%s", string(cacheRes)), registry)
   355  	}
   356  
   357  	newMetrics.RequestsQueueTimer["video"][true] = metrics.GetOrRegisterTimer("queued_requests.video.accepted", registry)
   358  	newMetrics.RequestsQueueTimer["video"][false] = metrics.GetOrRegisterTimer("queued_requests.video.rejected", registry)
   359  
   360  	newMetrics.TimeoutNotificationSuccess = metrics.GetOrRegisterMeter("timeout_notification.ok", registry)
   361  	newMetrics.TimeoutNotificationFailure = metrics.GetOrRegisterMeter("timeout_notification.failed", registry)
   362  
   363  	newMetrics.PrivacyCCPARequest = metrics.GetOrRegisterMeter("privacy.request.ccpa.specified", registry)
   364  	newMetrics.PrivacyCCPARequestOptOut = metrics.GetOrRegisterMeter("privacy.request.ccpa.opt-out", registry)
   365  	newMetrics.PrivacyCOPPARequest = metrics.GetOrRegisterMeter("privacy.request.coppa", registry)
   366  	newMetrics.PrivacyLMTRequest = metrics.GetOrRegisterMeter("privacy.request.lmt", registry)
   367  	for _, version := range TCFVersions() {
   368  		newMetrics.PrivacyTCFRequestVersion[version] = metrics.GetOrRegisterMeter(fmt.Sprintf("privacy.request.tcf.%s", string(version)), registry)
   369  	}
   370  
   371  	newMetrics.AdsCertRequestsSuccess = metrics.GetOrRegisterMeter("ads_cert_requests.ok", registry)
   372  	newMetrics.AdsCertRequestsFailure = metrics.GetOrRegisterMeter("ads_cert_requests.failed", registry)
   373  	newMetrics.adsCertSignTimer = metrics.GetOrRegisterTimer("ads_cert_sign_time", registry)
   374  
   375  	for module, stages := range moduleStageNames {
   376  		registerModuleMetrics(registry, module, stages, newMetrics.ModuleMetrics[module])
   377  	}
   378  
   379  	return newMetrics
   380  }
   381  
   382  func makeBlankOverheadTimerMetrics() map[OverheadType]metrics.Timer {
   383  	m := make(map[OverheadType]metrics.Timer)
   384  	overheads := OverheadTypes()
   385  	for idx := range overheads {
   386  		m[overheads[idx]] = &metrics.NilTimer{}
   387  	}
   388  	return m
   389  }
   390  
   391  // Part of setting up blank metrics, the adapter metrics.
   392  func makeBlankAdapterMetrics(disabledMetrics config.DisabledMetrics) *AdapterMetrics {
   393  	blankMeter := &metrics.NilMeter{}
   394  	newAdapter := &AdapterMetrics{
   395  		NoCookieMeter:     blankMeter,
   396  		ErrorMeters:       make(map[AdapterError]metrics.Meter),
   397  		NoBidMeter:        blankMeter,
   398  		GotBidsMeter:      blankMeter,
   399  		RequestTimer:      &metrics.NilTimer{},
   400  		PriceHistogram:    &metrics.NilHistogram{},
   401  		BidsReceivedMeter: blankMeter,
   402  		PanicMeter:        blankMeter,
   403  		MarkupMetrics:     makeBlankBidMarkupMetrics(),
   404  	}
   405  	if !disabledMetrics.AdapterConnectionMetrics {
   406  		newAdapter.ConnCreated = metrics.NilCounter{}
   407  		newAdapter.ConnReused = metrics.NilCounter{}
   408  		newAdapter.ConnWaitTime = &metrics.NilTimer{}
   409  	}
   410  	if !disabledMetrics.AdapterBuyerUIDScrubbed {
   411  		newAdapter.BuyerUIDScrubbed = blankMeter
   412  	}
   413  	if !disabledMetrics.AdapterGDPRRequestBlocked {
   414  		newAdapter.GDPRRequestBlocked = blankMeter
   415  	}
   416  	for _, err := range AdapterErrors() {
   417  		newAdapter.ErrorMeters[err] = blankMeter
   418  	}
   419  	return newAdapter
   420  }
   421  
   422  func makeBlankModuleStageMetrics(stages []string) map[string]*ModuleMetrics {
   423  	blankMetrics := map[string]*ModuleMetrics{}
   424  	for _, stage := range stages {
   425  		blankMetrics[stage] = makeBlankModuleMetrics()
   426  	}
   427  
   428  	return blankMetrics
   429  }
   430  
   431  func makeBlankModuleMetrics() *ModuleMetrics {
   432  	return &ModuleMetrics{
   433  		DurationTimer:         &metrics.NilTimer{},
   434  		CallCounter:           metrics.NilCounter{},
   435  		FailureCounter:        metrics.NilCounter{},
   436  		SuccessNoopCounter:    metrics.NilCounter{},
   437  		SuccessUpdateCounter:  metrics.NilCounter{},
   438  		SuccessRejectCounter:  metrics.NilCounter{},
   439  		ExecutionErrorCounter: metrics.NilCounter{},
   440  		TimeoutCounter:        metrics.NilCounter{},
   441  	}
   442  }
   443  
   444  func makeBlankBidMarkupMetrics() map[openrtb_ext.BidType]*MarkupDeliveryMetrics {
   445  	return map[openrtb_ext.BidType]*MarkupDeliveryMetrics{
   446  		openrtb_ext.BidTypeAudio:  makeBlankMarkupDeliveryMetrics(),
   447  		openrtb_ext.BidTypeBanner: makeBlankMarkupDeliveryMetrics(),
   448  		openrtb_ext.BidTypeNative: makeBlankMarkupDeliveryMetrics(),
   449  		openrtb_ext.BidTypeVideo:  makeBlankMarkupDeliveryMetrics(),
   450  	}
   451  }
   452  
   453  func makeBlankMarkupDeliveryMetrics() *MarkupDeliveryMetrics {
   454  	return &MarkupDeliveryMetrics{
   455  		AdmMeter:  &metrics.NilMeter{},
   456  		NurlMeter: &metrics.NilMeter{},
   457  	}
   458  }
   459  
   460  func makeOverheadTimerMetrics(registry metrics.Registry) map[OverheadType]metrics.Timer {
   461  	m := make(map[OverheadType]metrics.Timer)
   462  	overheads := OverheadTypes()
   463  	for idx := range overheads {
   464  		m[overheads[idx]] = metrics.GetOrRegisterTimer("request_over_head_time."+overheads[idx].String(), registry)
   465  	}
   466  	return m
   467  }
   468  
   469  func registerAdapterMetrics(registry metrics.Registry, adapterOrAccount string, exchange string, am *AdapterMetrics) {
   470  	am.NoCookieMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.no_cookie_requests", adapterOrAccount, exchange), registry)
   471  	am.NoBidMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.requests.nobid", adapterOrAccount, exchange), registry)
   472  	am.GotBidsMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.requests.gotbids", adapterOrAccount, exchange), registry)
   473  	am.RequestTimer = metrics.GetOrRegisterTimer(fmt.Sprintf("%[1]s.%[2]s.request_time", adapterOrAccount, exchange), registry)
   474  	am.PriceHistogram = metrics.GetOrRegisterHistogram(fmt.Sprintf("%[1]s.%[2]s.prices", adapterOrAccount, exchange), registry, metrics.NewExpDecaySample(1028, 0.015))
   475  	am.MarkupMetrics = map[openrtb_ext.BidType]*MarkupDeliveryMetrics{
   476  		openrtb_ext.BidTypeBanner: makeDeliveryMetrics(registry, adapterOrAccount+"."+exchange, openrtb_ext.BidTypeBanner),
   477  		openrtb_ext.BidTypeVideo:  makeDeliveryMetrics(registry, adapterOrAccount+"."+exchange, openrtb_ext.BidTypeVideo),
   478  		openrtb_ext.BidTypeAudio:  makeDeliveryMetrics(registry, adapterOrAccount+"."+exchange, openrtb_ext.BidTypeAudio),
   479  		openrtb_ext.BidTypeNative: makeDeliveryMetrics(registry, adapterOrAccount+"."+exchange, openrtb_ext.BidTypeNative),
   480  	}
   481  	am.ConnCreated = metrics.GetOrRegisterCounter(fmt.Sprintf("%[1]s.%[2]s.connections_created", adapterOrAccount, exchange), registry)
   482  	am.ConnReused = metrics.GetOrRegisterCounter(fmt.Sprintf("%[1]s.%[2]s.connections_reused", adapterOrAccount, exchange), registry)
   483  	am.ConnWaitTime = metrics.GetOrRegisterTimer(fmt.Sprintf("%[1]s.%[2]s.connection_wait_time", adapterOrAccount, exchange), registry)
   484  	for err := range am.ErrorMeters {
   485  		am.ErrorMeters[err] = metrics.GetOrRegisterMeter(fmt.Sprintf("%s.%s.requests.%s", adapterOrAccount, exchange, err), registry)
   486  	}
   487  	if adapterOrAccount != "adapter" {
   488  		am.BidsReceivedMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.bids_received", adapterOrAccount, exchange), registry)
   489  	}
   490  	am.PanicMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.requests.panic", adapterOrAccount, exchange), registry)
   491  	am.BuyerUIDScrubbed = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.buyeruid_scrubbed", adapterOrAccount, exchange), registry)
   492  	am.GDPRRequestBlocked = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.gdpr_request_blocked", adapterOrAccount, exchange), registry)
   493  
   494  	am.BidValidationCreativeSizeErrorMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.response.validation.size.err", adapterOrAccount, exchange), registry)
   495  	am.BidValidationCreativeSizeWarnMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.response.validation.size.warn", adapterOrAccount, exchange), registry)
   496  
   497  	am.BidValidationSecureMarkupErrorMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.response.validation.secure.err", adapterOrAccount, exchange), registry)
   498  	am.BidValidationSecureMarkupWarnMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("%[1]s.%[2]s.response.validation.secure.warn", adapterOrAccount, exchange), registry)
   499  }
   500  
   501  func registerModuleMetrics(registry metrics.Registry, module string, stages []string, mm map[string]*ModuleMetrics) {
   502  	for _, stage := range stages {
   503  		mm[stage].DurationTimer = metrics.GetOrRegisterTimer(fmt.Sprintf("modules.module.%s.stage.%s.duration", module, stage), registry)
   504  		mm[stage].CallCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("modules.module.%s.stage.%s.call", module, stage), registry)
   505  		mm[stage].FailureCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("modules.module.%s.stage.%s.failure", module, stage), registry)
   506  		mm[stage].SuccessNoopCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("modules.module.%s.stage.%s.success.noop", module, stage), registry)
   507  		mm[stage].SuccessUpdateCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("modules.module.%s.stage.%s.success.update", module, stage), registry)
   508  		mm[stage].SuccessRejectCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("modules.module.%s.stage.%s.success.reject", module, stage), registry)
   509  		mm[stage].ExecutionErrorCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("modules.module.%s.stage.%s.execution_error", module, stage), registry)
   510  		mm[stage].TimeoutCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("modules.module.%s.stage.%s.timeout", module, stage), registry)
   511  	}
   512  }
   513  
   514  func registerAccountModuleMetrics(registry metrics.Registry, id string, module string, mm *ModuleMetrics) {
   515  	mm.DurationTimer = metrics.GetOrRegisterTimer(fmt.Sprintf("account.%s.modules.module.%s.duration", id, module), registry)
   516  	mm.CallCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("account.%s.modules.module.%s.call", id, module), registry)
   517  	mm.FailureCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("account.%s.modules.module.%s.failure", id, module), registry)
   518  	mm.SuccessNoopCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("account.%s.modules.module.%s.success.noop", id, module), registry)
   519  	mm.SuccessUpdateCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("account.%s.modules.module.%s.success.update", id, module), registry)
   520  	mm.SuccessRejectCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("account.%s.modules.module.%s.success.reject", id, module), registry)
   521  	mm.ExecutionErrorCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("account.%s.modules.module.%s.execution_error", id, module), registry)
   522  	mm.TimeoutCounter = metrics.GetOrRegisterCounter(fmt.Sprintf("account.%s.modules.module.%s.timeout", id, module), registry)
   523  }
   524  
   525  func makeDeliveryMetrics(registry metrics.Registry, prefix string, bidType openrtb_ext.BidType) *MarkupDeliveryMetrics {
   526  	return &MarkupDeliveryMetrics{
   527  		AdmMeter:  metrics.GetOrRegisterMeter(prefix+"."+string(bidType)+".adm_bids_received", registry),
   528  		NurlMeter: metrics.GetOrRegisterMeter(prefix+"."+string(bidType)+".nurl_bids_received", registry),
   529  	}
   530  }
   531  
   532  // getAccountMetrics gets or registers the account metrics for account "id".
   533  // There is no getBlankAccountMetrics() as all metrics are generated dynamically.
   534  func (me *Metrics) getAccountMetrics(id string) *accountMetrics {
   535  	var am *accountMetrics
   536  	var ok bool
   537  
   538  	me.accountMetricsRWMutex.RLock()
   539  	am, ok = me.accountMetrics[id]
   540  	me.accountMetricsRWMutex.RUnlock()
   541  
   542  	if ok {
   543  		return am
   544  	}
   545  
   546  	me.accountMetricsRWMutex.Lock()
   547  	// Made sure to use defer as we have two exit points: we want to unlock the mutex as quickly as possible.
   548  	defer me.accountMetricsRWMutex.Unlock()
   549  
   550  	am, ok = me.accountMetrics[id]
   551  	if ok {
   552  		// Unlock and return as quickly as possible
   553  		return am
   554  	}
   555  	am = &accountMetrics{}
   556  	am.requestMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.requests", id), me.MetricsRegistry)
   557  	am.debugRequestMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.debug_requests", id), me.MetricsRegistry)
   558  	am.bidsReceivedMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.bids_received", id), me.MetricsRegistry)
   559  	am.priceHistogram = metrics.GetOrRegisterHistogram(fmt.Sprintf("account.%s.prices", id), me.MetricsRegistry, metrics.NewExpDecaySample(1028, 0.015))
   560  	am.adapterMetrics = make(map[string]*AdapterMetrics, len(me.exchanges))
   561  	am.moduleMetrics = make(map[string]*ModuleMetrics)
   562  	am.storedResponsesMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.stored_responses", id), me.MetricsRegistry)
   563  	if !me.MetricsDisabled.AccountAdapterDetails {
   564  		for _, a := range me.exchanges {
   565  			am.adapterMetrics[a] = makeBlankAdapterMetrics(me.MetricsDisabled)
   566  			registerAdapterMetrics(me.MetricsRegistry, fmt.Sprintf("account.%s", id), string(a), am.adapterMetrics[a])
   567  		}
   568  	}
   569  	am.bidValidationCreativeSizeMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.response.validation.size.err", id), me.MetricsRegistry)
   570  	am.bidValidationCreativeSizeWarnMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.response.validation.size.warn", id), me.MetricsRegistry)
   571  
   572  	am.bidValidationSecureMarkupMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.response.validation.secure.err", id), me.MetricsRegistry)
   573  	am.bidValidationSecureMarkupWarnMeter = metrics.GetOrRegisterMeter(fmt.Sprintf("account.%s.response.validation.secure.warn", id), me.MetricsRegistry)
   574  
   575  	if !me.MetricsDisabled.AccountModulesMetrics {
   576  		for _, mod := range me.modules {
   577  			am.moduleMetrics[mod] = makeBlankModuleMetrics()
   578  			registerAccountModuleMetrics(me.MetricsRegistry, id, mod, am.moduleMetrics[mod])
   579  		}
   580  	}
   581  
   582  	me.accountMetrics[id] = am
   583  
   584  	return am
   585  }
   586  
   587  // Implement the MetricsEngine interface
   588  
   589  // RecordRequest implements a part of the MetricsEngine interface
   590  func (me *Metrics) RecordRequest(labels Labels) {
   591  	me.RequestStatuses[labels.RType][labels.RequestStatus].Mark(1)
   592  	if labels.Source == DemandApp {
   593  		me.AppRequestMeter.Mark(1)
   594  	} else {
   595  		if labels.CookieFlag == CookieFlagNo {
   596  			// NOTE: Old behavior was log me.AMPNoCookieMeter here for AMP requests.
   597  			// AMP is still new and OpenRTB does not do this, so changing to match
   598  			// OpenRTB endpoint
   599  			me.NoCookieMeter.Mark(1)
   600  		}
   601  	}
   602  
   603  	// Handle the account metrics now.
   604  	am := me.getAccountMetrics(labels.PubID)
   605  	am.requestMeter.Mark(1)
   606  }
   607  
   608  func (me *Metrics) RecordDebugRequest(debugEnabled bool, pubID string) {
   609  	if debugEnabled {
   610  		me.DebugRequestMeter.Mark(1)
   611  		if pubID != PublisherUnknown {
   612  			am := me.getAccountMetrics(pubID)
   613  			if !me.MetricsDisabled.AccountDebug {
   614  				am.debugRequestMeter.Mark(1)
   615  			}
   616  		}
   617  	}
   618  }
   619  
   620  func (me *Metrics) RecordStoredResponse(pubId string) {
   621  	me.StoredResponsesMeter.Mark(1)
   622  	if pubId != PublisherUnknown && !me.MetricsDisabled.AccountStoredResponses {
   623  		me.getAccountMetrics(pubId).storedResponsesMeter.Mark(1)
   624  	}
   625  }
   626  
   627  func (me *Metrics) RecordImps(labels ImpLabels) {
   628  	me.ImpMeter.Mark(int64(1))
   629  	if labels.BannerImps {
   630  		me.ImpsTypeBanner.Mark(int64(1))
   631  	}
   632  	if labels.VideoImps {
   633  		me.ImpsTypeVideo.Mark(int64(1))
   634  	}
   635  	if labels.AudioImps {
   636  		me.ImpsTypeAudio.Mark(int64(1))
   637  	}
   638  	if labels.NativeImps {
   639  		me.ImpsTypeNative.Mark(int64(1))
   640  	}
   641  }
   642  
   643  func (me *Metrics) RecordConnectionAccept(success bool) {
   644  	if success {
   645  		me.ConnectionCounter.Inc(1)
   646  	} else {
   647  		me.ConnectionAcceptErrorMeter.Mark(1)
   648  	}
   649  }
   650  
   651  func (m *Metrics) RecordTMaxTimeout() {
   652  	m.TMaxTimeoutCounter.Inc(1)
   653  }
   654  
   655  func (me *Metrics) RecordConnectionClose(success bool) {
   656  	if success {
   657  		me.ConnectionCounter.Dec(1)
   658  	} else {
   659  		me.ConnectionCloseErrorMeter.Mark(1)
   660  	}
   661  }
   662  
   663  // RecordRequestTime implements a part of the MetricsEngine interface. The calling code is responsible
   664  // for determining the call duration.
   665  func (me *Metrics) RecordRequestTime(labels Labels, length time.Duration) {
   666  	// Only record times for successful requests, as we don't have labels to screen out bad requests.
   667  	if labels.RequestStatus == RequestStatusOK {
   668  		me.RequestTimer.Update(length)
   669  	}
   670  }
   671  
   672  // RecordStoredDataFetchTime implements a part of the MetricsEngine interface
   673  func (me *Metrics) RecordStoredDataFetchTime(labels StoredDataLabels, length time.Duration) {
   674  	me.StoredDataFetchTimer[labels.DataType][labels.DataFetchType].Update(length)
   675  }
   676  
   677  // RecordStoredDataError implements a part of the MetricsEngine interface
   678  func (me *Metrics) RecordStoredDataError(labels StoredDataLabels) {
   679  	me.StoredDataErrorMeter[labels.DataType][labels.Error].Mark(1)
   680  }
   681  
   682  // RecordAdapterPanic implements a part of the MetricsEngine interface
   683  func (me *Metrics) RecordAdapterPanic(labels AdapterLabels) {
   684  	adapterStr := string(labels.Adapter)
   685  	lowerCaseAdapterName := strings.ToLower(adapterStr)
   686  	am, ok := me.AdapterMetrics[lowerCaseAdapterName]
   687  	if !ok {
   688  		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
   689  		return
   690  	}
   691  	am.PanicMeter.Mark(1)
   692  }
   693  
   694  // RecordAdapterRequest implements a part of the MetricsEngine interface
   695  func (me *Metrics) RecordAdapterRequest(labels AdapterLabels) {
   696  	adapterStr := string(labels.Adapter)
   697  	lowerCaseAdapter := strings.ToLower(adapterStr)
   698  	am, ok := me.AdapterMetrics[lowerCaseAdapter]
   699  	if !ok {
   700  		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
   701  		return
   702  	}
   703  
   704  	aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[lowerCaseAdapter]
   705  	switch labels.AdapterBids {
   706  	case AdapterBidNone:
   707  		am.NoBidMeter.Mark(1)
   708  		if ok {
   709  			aam.NoBidMeter.Mark(1)
   710  		}
   711  	case AdapterBidPresent:
   712  		am.GotBidsMeter.Mark(1)
   713  		if ok {
   714  			aam.GotBidsMeter.Mark(1)
   715  		}
   716  	default:
   717  		glog.Warningf("No go-metrics logged for AdapterBids value: %s", labels.AdapterBids)
   718  	}
   719  	for errType := range labels.AdapterErrors {
   720  		am.ErrorMeters[errType].Mark(1)
   721  	}
   722  
   723  	if labels.CookieFlag == CookieFlagNo {
   724  		am.NoCookieMeter.Mark(1)
   725  	}
   726  }
   727  
   728  // Keeps track of created and reused connections to adapter bidders and the time from the
   729  // connection request, to the connection creation, or reuse from the pool across all engines
   730  func (me *Metrics) RecordAdapterConnections(adapterName openrtb_ext.BidderName,
   731  	connWasReused bool,
   732  	connWaitTime time.Duration) {
   733  
   734  	if me.MetricsDisabled.AdapterConnectionMetrics {
   735  		return
   736  	}
   737  	lowerCaseAdapterName := strings.ToLower(string(adapterName))
   738  	am, ok := me.AdapterMetrics[lowerCaseAdapterName]
   739  	if !ok {
   740  		glog.Errorf("Trying to log adapter connection metrics for %s: adapter not found", string(adapterName))
   741  		return
   742  	}
   743  
   744  	if connWasReused {
   745  		am.ConnReused.Inc(1)
   746  	} else {
   747  		am.ConnCreated.Inc(1)
   748  	}
   749  	am.ConnWaitTime.Update(connWaitTime)
   750  }
   751  
   752  func (me *Metrics) RecordDNSTime(dnsLookupTime time.Duration) {
   753  	me.DNSLookupTimer.Update(dnsLookupTime)
   754  }
   755  
   756  func (me *Metrics) RecordTLSHandshakeTime(tlsHandshakeTime time.Duration) {
   757  	me.TLSHandshakeTimer.Update(tlsHandshakeTime)
   758  }
   759  
   760  func (me *Metrics) RecordBidderServerResponseTime(bidderServerResponseTime time.Duration) {
   761  	me.BidderServerResponseTimer.Update(bidderServerResponseTime)
   762  }
   763  
   764  // RecordAdapterBidReceived implements a part of the MetricsEngine interface.
   765  // This tracks how many bids from each Bidder use `adm` vs. `nurl.
   766  func (me *Metrics) RecordAdapterBidReceived(labels AdapterLabels, bidType openrtb_ext.BidType, hasAdm bool) {
   767  	adapterStr := string(labels.Adapter)
   768  	lowerCaseAdapterName := strings.ToLower(adapterStr)
   769  	am, ok := me.AdapterMetrics[lowerCaseAdapterName]
   770  	if !ok {
   771  		glog.Errorf("Trying to run adapter bid metrics on %s: adapter metrics not found", adapterStr)
   772  		return
   773  	}
   774  
   775  	// Adapter metrics
   776  	am.BidsReceivedMeter.Mark(1)
   777  	// Account-Adapter metrics
   778  	if aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[lowerCaseAdapterName]; ok {
   779  		aam.BidsReceivedMeter.Mark(1)
   780  	}
   781  
   782  	if metricsForType, ok := am.MarkupMetrics[bidType]; ok {
   783  		if hasAdm {
   784  			metricsForType.AdmMeter.Mark(1)
   785  		} else {
   786  			metricsForType.NurlMeter.Mark(1)
   787  		}
   788  	} else {
   789  		glog.Errorf("bid/adm metrics map entry does not exist for type %s. This is a bug, and should be reported.", bidType)
   790  	}
   791  }
   792  
   793  // RecordAdapterPrice implements a part of the MetricsEngine interface. Generates a histogram of winning bid prices
   794  func (me *Metrics) RecordAdapterPrice(labels AdapterLabels, cpm float64) {
   795  	adapterStr := string(labels.Adapter)
   796  	lowercaseAdapter := strings.ToLower(adapterStr)
   797  	am, ok := me.AdapterMetrics[lowercaseAdapter]
   798  	if !ok {
   799  		glog.Errorf("Trying to run adapter price metrics on %s: adapter metrics not found", adapterStr)
   800  		return
   801  	}
   802  	// Adapter metrics
   803  	am.PriceHistogram.Update(int64(cpm))
   804  	// Account-Adapter metrics
   805  	if aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[lowercaseAdapter]; ok {
   806  		aam.PriceHistogram.Update(int64(cpm))
   807  	}
   808  }
   809  
   810  // RecordAdapterTime implements a part of the MetricsEngine interface. Records the adapter response time
   811  func (me *Metrics) RecordAdapterTime(labels AdapterLabels, length time.Duration) {
   812  	adapterStr := string(labels.Adapter)
   813  	lowercaseAdapter := strings.ToLower(adapterStr)
   814  	am, ok := me.AdapterMetrics[lowercaseAdapter]
   815  	if !ok {
   816  		glog.Errorf("Trying to run adapter latency metrics on %s: adapter metrics not found", string(labels.Adapter))
   817  		return
   818  	}
   819  	// Adapter metrics
   820  	am.RequestTimer.Update(length)
   821  	// Account-Adapter metrics
   822  	if aam, ok := me.getAccountMetrics(labels.PubID).adapterMetrics[lowercaseAdapter]; ok {
   823  		aam.RequestTimer.Update(length)
   824  	}
   825  }
   826  
   827  // RecordOverheadTime implements a part of the MetricsEngine interface. Records the adapter overhead time
   828  func (me *Metrics) RecordOverheadTime(overhead OverheadType, length time.Duration) {
   829  	me.OverheadTimer[overhead].Update(length)
   830  }
   831  
   832  // RecordCookieSync implements a part of the MetricsEngine interface. Records a cookie sync request
   833  func (me *Metrics) RecordCookieSync(status CookieSyncStatus) {
   834  	me.CookieSyncMeter.Mark(1)
   835  	if meter, exists := me.CookieSyncStatusMeter[status]; exists {
   836  		meter.Mark(1)
   837  	}
   838  }
   839  
   840  // RecordSyncerRequest implements a part of the MetricsEngine interface. Records a cookie sync syncer request and status
   841  func (me *Metrics) RecordSyncerRequest(key string, status SyncerCookieSyncStatus) {
   842  	if keyMeter, exists := me.SyncerRequestsMeter[key]; exists {
   843  		if statusMeter, exists := keyMeter[status]; exists {
   844  			statusMeter.Mark(1)
   845  		}
   846  	}
   847  }
   848  
   849  // RecordSetUid implements a part of the MetricsEngine interface. Records a set uid sync request
   850  func (me *Metrics) RecordSetUid(status SetUidStatus) {
   851  	me.SetUidMeter.Mark(1)
   852  	if meter, exists := me.SetUidStatusMeter[status]; exists {
   853  		meter.Mark(1)
   854  	}
   855  }
   856  
   857  // RecordSyncerSet implements a part of the MetricsEngine interface. Records a set uid sync request and status
   858  func (me *Metrics) RecordSyncerSet(key string, status SyncerSetUidStatus) {
   859  	if keyMeter, exists := me.SyncerSetsMeter[key]; exists {
   860  		if statusMeter, exists := keyMeter[status]; exists {
   861  			statusMeter.Mark(1)
   862  		}
   863  	}
   864  }
   865  
   866  // RecordStoredReqCacheResult implements a part of the MetricsEngine interface. Records the
   867  // cache hits and misses when looking up stored requests
   868  func (me *Metrics) RecordStoredReqCacheResult(cacheResult CacheResult, inc int) {
   869  	me.StoredReqCacheMeter[cacheResult].Mark(int64(inc))
   870  }
   871  
   872  // RecordStoredImpCacheResult implements a part of the MetricsEngine interface. Records the
   873  // cache hits and misses when looking up stored impressions.
   874  func (me *Metrics) RecordStoredImpCacheResult(cacheResult CacheResult, inc int) {
   875  	me.StoredImpCacheMeter[cacheResult].Mark(int64(inc))
   876  }
   877  
   878  // RecordAccountCacheResult implements a part of the MetricsEngine interface. Records the
   879  // cache hits and misses when looking up accounts.
   880  func (me *Metrics) RecordAccountCacheResult(cacheResult CacheResult, inc int) {
   881  	me.AccountCacheMeter[cacheResult].Mark(int64(inc))
   882  }
   883  
   884  // RecordPrebidCacheRequestTime implements a part of the MetricsEngine interface. Records the
   885  // amount of time taken to store the auction result in Prebid Cache.
   886  func (me *Metrics) RecordPrebidCacheRequestTime(success bool, length time.Duration) {
   887  	if success {
   888  		me.PrebidCacheRequestTimerSuccess.Update(length)
   889  	} else {
   890  		me.PrebidCacheRequestTimerError.Update(length)
   891  	}
   892  }
   893  
   894  func (me *Metrics) RecordRequestQueueTime(success bool, requestType RequestType, length time.Duration) {
   895  	if requestType == ReqTypeVideo { //remove this check when other request types are supported
   896  		me.RequestsQueueTimer[requestType][success].Update(length)
   897  	}
   898  
   899  }
   900  
   901  func (me *Metrics) RecordTimeoutNotice(success bool) {
   902  	if success {
   903  		me.TimeoutNotificationSuccess.Mark(1)
   904  	} else {
   905  		me.TimeoutNotificationFailure.Mark(1)
   906  	}
   907  }
   908  
   909  func (me *Metrics) RecordRequestPrivacy(privacy PrivacyLabels) {
   910  	if privacy.CCPAProvided {
   911  		me.PrivacyCCPARequest.Mark(1)
   912  		if privacy.CCPAEnforced {
   913  			me.PrivacyCCPARequestOptOut.Mark(1)
   914  		}
   915  	}
   916  
   917  	if privacy.COPPAEnforced {
   918  		me.PrivacyCOPPARequest.Mark(1)
   919  	}
   920  
   921  	if privacy.GDPREnforced {
   922  		if metric, ok := me.PrivacyTCFRequestVersion[privacy.GDPRTCFVersion]; ok {
   923  			metric.Mark(1)
   924  		} else {
   925  			me.PrivacyTCFRequestVersion[TCFVersionErr].Mark(1)
   926  		}
   927  	}
   928  
   929  	if privacy.LMTEnforced {
   930  		me.PrivacyLMTRequest.Mark(1)
   931  	}
   932  }
   933  
   934  func (me *Metrics) RecordAdapterBuyerUIDScrubbed(adapterName openrtb_ext.BidderName) {
   935  	adapterStr := adapterName.String()
   936  	if me.MetricsDisabled.AdapterBuyerUIDScrubbed {
   937  		return
   938  	}
   939  
   940  	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
   941  	if !ok {
   942  		glog.Errorf("Trying to log adapter buyeruid scrubbed metric for %s: adapter not found", adapterStr)
   943  		return
   944  	}
   945  
   946  	am.BuyerUIDScrubbed.Mark(1)
   947  }
   948  
   949  func (me *Metrics) RecordAdapterGDPRRequestBlocked(adapterName openrtb_ext.BidderName) {
   950  	adapterStr := string(adapterName)
   951  	if me.MetricsDisabled.AdapterGDPRRequestBlocked {
   952  		return
   953  	}
   954  
   955  	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
   956  	if !ok {
   957  		glog.Errorf("Trying to log adapter GDPR request blocked metric for %s: adapter not found", adapterStr)
   958  		return
   959  	}
   960  
   961  	am.GDPRRequestBlocked.Mark(1)
   962  }
   963  
   964  func (me *Metrics) RecordAdsCertReq(success bool) {
   965  	if success {
   966  		me.AdsCertRequestsSuccess.Mark(1)
   967  	} else {
   968  		me.AdsCertRequestsFailure.Mark(1)
   969  	}
   970  }
   971  
   972  func (me *Metrics) RecordAdsCertSignTime(adsCertSignTime time.Duration) {
   973  	me.adsCertSignTimer.Update(adsCertSignTime)
   974  }
   975  
   976  func (me *Metrics) RecordBidValidationCreativeSizeError(adapter openrtb_ext.BidderName, pubID string) {
   977  	adapterStr := string(adapter)
   978  	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
   979  	if !ok {
   980  		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
   981  		return
   982  	}
   983  	am.BidValidationCreativeSizeErrorMeter.Mark(1)
   984  
   985  	aam := me.getAccountMetrics(pubID)
   986  	if !me.MetricsDisabled.AccountAdapterDetails {
   987  		aam.bidValidationCreativeSizeMeter.Mark(1)
   988  	}
   989  }
   990  
   991  func (me *Metrics) RecordBidValidationCreativeSizeWarn(adapter openrtb_ext.BidderName, pubID string) {
   992  	adapterStr := string(adapter)
   993  	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
   994  	if !ok {
   995  		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
   996  		return
   997  	}
   998  	am.BidValidationCreativeSizeWarnMeter.Mark(1)
   999  
  1000  	aam := me.getAccountMetrics(pubID)
  1001  	if !me.MetricsDisabled.AccountAdapterDetails {
  1002  		aam.bidValidationCreativeSizeWarnMeter.Mark(1)
  1003  	}
  1004  }
  1005  
  1006  func (me *Metrics) RecordBidValidationSecureMarkupError(adapter openrtb_ext.BidderName, pubID string) {
  1007  	adapterStr := string(adapter)
  1008  	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
  1009  	if !ok {
  1010  		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
  1011  		return
  1012  	}
  1013  	am.BidValidationSecureMarkupErrorMeter.Mark(1)
  1014  
  1015  	aam := me.getAccountMetrics(pubID)
  1016  	if !me.MetricsDisabled.AccountAdapterDetails {
  1017  		aam.bidValidationSecureMarkupMeter.Mark(1)
  1018  	}
  1019  }
  1020  
  1021  func (me *Metrics) RecordBidValidationSecureMarkupWarn(adapter openrtb_ext.BidderName, pubID string) {
  1022  	adapterStr := string(adapter)
  1023  	am, ok := me.AdapterMetrics[strings.ToLower(adapterStr)]
  1024  	if !ok {
  1025  		glog.Errorf("Trying to run adapter metrics on %s: adapter metrics not found", adapterStr)
  1026  		return
  1027  	}
  1028  	am.BidValidationSecureMarkupWarnMeter.Mark(1)
  1029  
  1030  	aam := me.getAccountMetrics(pubID)
  1031  	if !me.MetricsDisabled.AccountAdapterDetails {
  1032  		aam.bidValidationSecureMarkupWarnMeter.Mark(1)
  1033  	}
  1034  }
  1035  
  1036  func (me *Metrics) RecordModuleCalled(labels ModuleLabels, duration time.Duration) {
  1037  	mm, err := me.getModuleMetric(labels)
  1038  	if err != nil {
  1039  		return
  1040  	}
  1041  
  1042  	// Module metrics
  1043  	mm.CallCounter.Inc(1)
  1044  	mm.DurationTimer.Update(duration)
  1045  
  1046  	// Account-Module metrics
  1047  	if labels.AccountID != "" && labels.AccountID != PublisherUnknown {
  1048  		if aam, ok := me.getAccountMetrics(labels.AccountID).moduleMetrics[labels.Module]; ok {
  1049  			aam.CallCounter.Inc(1)
  1050  			aam.DurationTimer.Update(duration)
  1051  		}
  1052  	}
  1053  }
  1054  
  1055  func (me *Metrics) RecordModuleFailed(labels ModuleLabels) {
  1056  	mm, err := me.getModuleMetric(labels)
  1057  	if err != nil {
  1058  		return
  1059  	}
  1060  
  1061  	// Module metrics
  1062  	mm.FailureCounter.Inc(1)
  1063  
  1064  	// Account-Module metrics
  1065  	if labels.AccountID != "" && labels.AccountID != PublisherUnknown {
  1066  		if aam, ok := me.getAccountMetrics(labels.AccountID).moduleMetrics[labels.Module]; ok {
  1067  			aam.FailureCounter.Inc(1)
  1068  		}
  1069  	}
  1070  }
  1071  
  1072  func (me *Metrics) RecordModuleSuccessNooped(labels ModuleLabels) {
  1073  	mm, err := me.getModuleMetric(labels)
  1074  	if err != nil {
  1075  		return
  1076  	}
  1077  
  1078  	// Module metrics
  1079  	mm.SuccessNoopCounter.Inc(1)
  1080  
  1081  	// Account-Module metrics
  1082  	if labels.AccountID != "" && labels.AccountID != PublisherUnknown {
  1083  		if aam, ok := me.getAccountMetrics(labels.AccountID).moduleMetrics[labels.Module]; ok {
  1084  			aam.SuccessNoopCounter.Inc(1)
  1085  		}
  1086  	}
  1087  }
  1088  
  1089  func (me *Metrics) RecordModuleSuccessUpdated(labels ModuleLabels) {
  1090  	mm, err := me.getModuleMetric(labels)
  1091  	if err != nil {
  1092  		return
  1093  	}
  1094  
  1095  	// Module metrics
  1096  	mm.SuccessUpdateCounter.Inc(1)
  1097  
  1098  	// Account-Module metrics
  1099  	if labels.AccountID != "" && labels.AccountID != PublisherUnknown {
  1100  		if aam, ok := me.getAccountMetrics(labels.AccountID).moduleMetrics[labels.Module]; ok {
  1101  			aam.SuccessUpdateCounter.Inc(1)
  1102  		}
  1103  	}
  1104  }
  1105  
  1106  func (me *Metrics) RecordModuleSuccessRejected(labels ModuleLabels) {
  1107  	mm, err := me.getModuleMetric(labels)
  1108  	if err != nil {
  1109  		return
  1110  	}
  1111  
  1112  	// Module metrics
  1113  	mm.SuccessRejectCounter.Inc(1)
  1114  
  1115  	// Account-Module metrics
  1116  	if labels.AccountID != "" && labels.AccountID != PublisherUnknown {
  1117  		if aam, ok := me.getAccountMetrics(labels.AccountID).moduleMetrics[labels.Module]; ok {
  1118  			aam.SuccessRejectCounter.Inc(1)
  1119  		}
  1120  	}
  1121  }
  1122  
  1123  func (me *Metrics) RecordModuleExecutionError(labels ModuleLabels) {
  1124  	mm, err := me.getModuleMetric(labels)
  1125  	if err != nil {
  1126  		return
  1127  	}
  1128  
  1129  	// Module metrics
  1130  	mm.ExecutionErrorCounter.Inc(1)
  1131  
  1132  	// Account-Module metrics
  1133  	if labels.AccountID != "" && labels.AccountID != PublisherUnknown {
  1134  		if aam, ok := me.getAccountMetrics(labels.AccountID).moduleMetrics[labels.Module]; ok {
  1135  			aam.ExecutionErrorCounter.Inc(1)
  1136  		}
  1137  	}
  1138  }
  1139  
  1140  func (me *Metrics) RecordModuleTimeout(labels ModuleLabels) {
  1141  	mm, err := me.getModuleMetric(labels)
  1142  	if err != nil {
  1143  		return
  1144  	}
  1145  
  1146  	// Module metrics
  1147  	mm.TimeoutCounter.Inc(1)
  1148  
  1149  	// Account-Module metrics
  1150  	if labels.AccountID != "" && labels.AccountID != PublisherUnknown {
  1151  		if aam, ok := me.getAccountMetrics(labels.AccountID).moduleMetrics[labels.Module]; ok {
  1152  			aam.TimeoutCounter.Inc(1)
  1153  		}
  1154  	}
  1155  }
  1156  
  1157  func (me *Metrics) getModuleMetric(labels ModuleLabels) (*ModuleMetrics, error) {
  1158  	mm, ok := me.ModuleMetrics[labels.Module][labels.Stage]
  1159  	if !ok {
  1160  		err := fmt.Errorf("Trying to run module %s metrics for stage %s: module metrics not found", labels.Module, labels.Stage)
  1161  		glog.Errorf(err.Error())
  1162  		return nil, err
  1163  	}
  1164  
  1165  	return mm, nil
  1166  }