component = StatsUtils::normalizeString( $component ); $this->cache = $cache; $this->emitter = $emitter; $this->logger = $logger; $this->validateInstanceConfig(); } /** * Throw exception on invalid instance configuration. * * @return void */ private function validateInstanceConfig(): void { if ( $this->component == '' ) { throw new InvalidArgumentException( 'Stats: component cannot be empty.' ); } } /** * Adds a label key-value pair to all metrics created by this StatsFactory instance. * * @param string $key * @param string $value * @return $this */ public function withStaticLabel( string $key, string $value ): StatsFactory { if ( count( $this->cache->getAllMetrics() ) > 0 ) { throw new IllegalOperationException( 'Stats: cannot set static labels when metrics are in the cache.' ); } $key = StatsUtils::normalizeString( $key ); StatsUtils::validateLabelKey( $key ); $this->staticLabelKeys[] = $key; $this->staticLabelValues[] = StatsUtils::normalizeString( $value ); return $this; } public function withStatsdDataFactory( IBufferingStatsdDataFactory $statsdDataFactory ): StatsFactory { $this->statsdDataFactory = $statsdDataFactory; return $this; } /** * Makes a new CounterMetric or fetches one from cache. * * If a collision occurs, returns a NullMetric to suppress exceptions. * * @param string $name * @return CounterMetric|NullMetric */ public function getCounter( string $name ) { return $this->getMetric( $name, CounterMetric::class ); } /** * Makes a new GaugeMetric or fetches one from cache. * * If a collision occurs, returns a NullMetric to suppress exceptions. * * @param string $name * @return GaugeMetric|NullMetric */ public function getGauge( string $name ) { return $this->getMetric( $name, GaugeMetric::class ); } /** * Makes a new TimingMetric or fetches one from cache. * * If a collision occurs, returns a NullMetric to suppress exceptions. * * @param string $name * @return TimingMetric|NullMetric */ public function getTiming( string $name ) { return $this->getMetric( $name, TimingMetric::class ); } /** * Send all buffered metrics to the target and destroy the cache. */ public function flush(): void { $this->emitter->send(); $this->cache->clear(); } /** * Fetches a metric from cache or makes a new metric. * * If a metric name collision occurs, returns a NullMetric to suppress runtime exceptions. * * @param string $name * @param string $className * @return CounterMetric|TimingMetric|GaugeMetric|NullMetric */ private function getMetric( string $name, string $className ) { $name = StatsUtils::normalizeString( $name ); StatsUtils::validateMetricName( $name ); try { $metric = $this->cache->get( $this->component, $name, $className ); } catch ( TypeError | InvalidArgumentException | InvalidConfigurationException $ex ) { // Log the condition and give the caller something that will absorb calls. trigger_error( $ex->getMessage(), E_USER_WARNING ); return new NullMetric; } if ( $metric === null ) { $baseMetric = new BaseMetric( $this->component, $name ); $metric = new $className( $baseMetric ->withStatsdDataFactory( $this->statsdDataFactory ) ->withStaticLabels( $this->staticLabelKeys, $this->staticLabelValues ), $this->logger ); $this->cache->set( $this->component, $name, $metric ); } return $metric->fresh(); } }