import CloudWatch , { Dimension , DimensionName } from 'aws-sdk/clients/cloudwatch' ; import { ServiceConfigurationOptions } from 'aws-sdk/lib/service' ; import { Logger } from './log-delivery' ; import { AwsTaskWorkerPool , ExtendedClient , SessionProxy } from './proxy' ; import { Action , MetricTypes , StandardUnit } from './interface' ; import { BaseHandlerException } from './exceptions' ; import { Queue } from './utils' ; const METRIC_NAMESPACE_ROOT = 'AWS/CloudFormation' ; export type DimensionRecord = Record < DimensionName , string > ; export function formatDimensions ( dimensions ) { const formatted = [ ] ; for ( const key in dimensions ) { const value = dimensions [ key ] ; const dimension = { Name : key , Value : value , } ; formatted . push ( dimension ) ; } return formatted ; } /**
 * A cloudwatch based metric publisher.
 * Given a resource type and session,
 * this publisher will publish metrics to CloudWatch.
 * Can be used with the MetricsPublisherProxy.
 */ export class MetricsPublisher { private resourceNamespace : string ; private client : ExtendedClient < CloudWatch > ; constructor ( private readonly session , private readonly logger , private readonly resourceType , protected readonly workerPool ? ) { this . resourceNamespace = resourceType . replace ( /::/g , '/' ) ; } public refreshClient ( options ? ) { this . client = this . session . client ( CloudWatch , options , this . workerPool ) ; } async publishMetric ( metricName , dimensions , unit , value , timestamp ) { if ( ! this . client ) { throw Error ( 'CloudWatch client was not initialized. You must call refreshClient() first.' ) ; } try { const metric = await this . client . makeRequestPromise ( 'putMetricData' , { Namespace : `${ METRIC_NAMESPACE_ROOT }/${ this . resourceNamespace }` , MetricData : [ { MetricName : metricName , Dimensions : formatDimensions ( dimensions ) , Unit : unit , Timestamp : timestamp , Value : value , } , ] , } ) ; this . log ( 'Response from "putMetricData"' , metric ) ; } catch ( err ) { if ( err . retryable ) { throw err ; } else { this . log ( `An error occurred while publishing metrics: ${ err . message }` ) ; } } } /**
     * Publishes an exception based metric
     */ async publishExceptionMetric ( timestamp , action , error ) { const dimensions = { DimensionKeyActionType : action , DimensionKeyExceptionType : ( error as BaseHandlerException ) . errorCode || error . constructor . name , DimensionKeyResourceType : this . resourceType , } ; return this . publishMetric ( MetricTypes . HandlerException , dimensions , StandardUnit . Count , 1.0 , timestamp ) ; } /**
     * Publishes a metric related to invocations
     */ async publishInvocationMetric ( timestamp , action ) { const dimensions = { DimensionKeyActionType : action , DimensionKeyResourceType : this . resourceType , } ; return this . publishMetric ( MetricTypes . HandlerInvocationCount , dimensions , StandardUnit . Count , 1.0 , timestamp ) ; } /**
     * Publishes an duration metric
     */ async publishDurationMetric ( timestamp , action , milliseconds ) { const dimensions = { DimensionKeyActionType : action , DimensionKeyResourceType : this . resourceType , } ; return this . publishMetric ( MetricTypes . HandlerInvocationDuration , dimensions , StandardUnit . Milliseconds , milliseconds , timestamp ) ; } /**
     * Publishes an log delivery exception metric
     */ async publishLogDeliveryExceptionMetric ( timestamp , error ) { const dimensions = { DimensionKeyActionType : 'ProviderLogDelivery' , DimensionKeyExceptionType : ( error as BaseHandlerException ) . errorCode || error . constructor . name , DimensionKeyResourceType : this . resourceType , } ; try { return await this . publishMetric ( MetricTypes . HandlerException , dimensions , StandardUnit . Count , 1.0 , timestamp ) ; } catch ( err ) { this . log ( err ) ; } return Promise . resolve ( null ) ; } private log ( message ? , ... optionalParams ) { if ( this . logger ) { this . logger . log ( message , ... optionalParams ) ; } } } /**
 * A proxy for publishing metrics to multiple publishers.
 * Iterates over available publishers and publishes.
 */ export class MetricsPublisherProxy { private publishers : Array < MetricsPublisher > = [ ] ; private queue = new Queue ( ) ; /**
     * Adds a metrics publisher to the list of publishers
     */ addMetricsPublisher ( metricsPublisher ? ) { if ( metricsPublisher ) { this . publishers . push ( metricsPublisher ) ; } } /**
     * Publishes an exception based metric to the list of publishers
     */ async publishExceptionMetric ( timestamp , action , error ) { for ( const publisher of this . publishers ) { await this . queue . enqueue ( ( ) => publisher . publishExceptionMetric ( timestamp , action , error ) ) ; } } /**
     * Publishes a metric related to invocations to the list of publishers
     */ async publishInvocationMetric ( timestamp , action ) { for ( const publisher of this . publishers ) { await this . queue . enqueue ( ( ) => publisher . publishInvocationMetric ( timestamp , action ) ) ; } } /**
     * Publishes a duration metric to the list of publishers
     */ async publishDurationMetric ( timestamp , action , milliseconds ) { for ( const publisher of this . publishers ) { await this . queue . enqueue ( ( ) => publisher . publishDurationMetric ( timestamp , action , milliseconds ) ) ; } } /**
     * Publishes a log delivery exception metric to the list of publishers
     */ async publishLogDeliveryExceptionMetric ( timestamp , error ) { for ( const publisher of this . publishers ) { await this . queue . enqueue ( ( ) => publisher . publishLogDeliveryExceptionMetric ( timestamp , error ) ) ; } } }