From ad92af4f122f17fa17feb2efbfc5446155f40b3d Mon Sep 17 00:00:00 2001
From: niko-achilles <niko.achilles.kokkinos@gmail.com>
Date: Sat, 11 Mar 2023 15:02:19 +0200
Subject: [PATCH 1/8] feat(metrics): type concept support high resolution
 metrics (#1277)

---
 packages/metrics/src/Metrics.ts               | 13 ++--
 packages/metrics/src/MetricsInterface.ts      |  4 +-
 .../metrics/src/types/MetricResolution.ts     |  8 +++
 packages/metrics/src/types/Metrics.ts         |  6 +-
 packages/metrics/src/types/index.ts           |  3 +-
 packages/metrics/tests/unit/Metrics.test.ts   | 60 ++++++++++++++++++-
 .../tests/unit/middleware/middy.test.ts       | 12 ++--
 7 files changed, 88 insertions(+), 18 deletions(-)
 create mode 100644 packages/metrics/src/types/MetricResolution.ts

diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts
index dbde8e0438..a9ee392d62 100644
--- a/packages/metrics/src/Metrics.ts
+++ b/packages/metrics/src/Metrics.ts
@@ -11,11 +11,13 @@ import {
   ExtraOptions,
   MetricUnit,
   MetricUnits,
+  MetricResolution
 } from './types';
 
 const MAX_METRICS_SIZE = 100;
 const MAX_DIMENSION_COUNT = 29;
 const DEFAULT_NAMESPACE = 'default_namespace';
+const DEFAULT_METRIC_RESOLUTION = MetricResolution.Standard; 
 
 /**
  * ## Intro
@@ -169,8 +171,9 @@ class Metrics extends Utility implements MetricsInterface {
    * @param unit
    * @param value
    */
-  public addMetric(name: string, unit: MetricUnit, value: number): void {
-    this.storeMetric(name, unit, value);
+
+  public addMetric(name: string, unit: MetricUnit, value: number, resolution?: MetricResolution): void {
+    this.storeMetric(name, unit, value, resolution ?? DEFAULT_METRIC_RESOLUTION );
     if (this.isSingleMetric) this.publishStoredMetrics();
   }
 
@@ -322,6 +325,7 @@ class Metrics extends Utility implements MetricsInterface {
     const metricDefinitions = Object.values(this.storedMetrics).map((metricDefinition) => ({
       Name: metricDefinition.name,
       Unit: metricDefinition.unit,
+      StorageResolution: metricDefinition.resolution
     }));
     if (metricDefinitions.length === 0 && this.shouldThrowOnEmptyMetrics) {
       throw new RangeError('The number of metrics recorded must be higher than zero');
@@ -479,7 +483,7 @@ class Metrics extends Utility implements MetricsInterface {
     }
   }
 
-  private storeMetric(name: string, unit: MetricUnit, value: number): void {
+  private storeMetric(name: string, unit: MetricUnit, value: number, resolution: MetricResolution): void {
     if (Object.keys(this.storedMetrics).length >= MAX_METRICS_SIZE) {
       this.publishStoredMetrics();
     }
@@ -489,6 +493,7 @@ class Metrics extends Utility implements MetricsInterface {
         unit,
         value,
         name,
+        resolution
       };
     } else {
       const storedMetric = this.storedMetrics[name];
@@ -501,4 +506,4 @@ class Metrics extends Utility implements MetricsInterface {
 
 }
 
-export { Metrics, MetricUnits };
+export { Metrics, MetricUnits, MetricResolution };
diff --git a/packages/metrics/src/MetricsInterface.ts b/packages/metrics/src/MetricsInterface.ts
index cda2fd577e..f7ad653b43 100644
--- a/packages/metrics/src/MetricsInterface.ts
+++ b/packages/metrics/src/MetricsInterface.ts
@@ -1,11 +1,11 @@
 import { Metrics } from './Metrics';
-import { MetricUnit, EmfOutput, HandlerMethodDecorator, Dimensions, MetricsOptions } from './types';
+import { MetricUnit, MetricResolution, EmfOutput, HandlerMethodDecorator, Dimensions, MetricsOptions } from './types';
 
 interface MetricsInterface {
   addDimension(name: string, value: string): void
   addDimensions(dimensions: {[key: string]: string}): void
   addMetadata(key: string, value: string): void
-  addMetric(name: string, unit:MetricUnit, value:number): void
+  addMetric(name: string, unit:MetricUnit, value:number, resolution?: MetricResolution): void
   clearDimensions(): void
   clearMetadata(): void
   clearMetrics(): void
diff --git a/packages/metrics/src/types/MetricResolution.ts b/packages/metrics/src/types/MetricResolution.ts
new file mode 100644
index 0000000000..76065be623
--- /dev/null
+++ b/packages/metrics/src/types/MetricResolution.ts
@@ -0,0 +1,8 @@
+const MetricResolution = {
+  Standard: 60,
+  High: 1,
+} as const;
+
+type MetricResolution = typeof MetricResolution[keyof typeof MetricResolution];
+
+export { MetricResolution };
\ No newline at end of file
diff --git a/packages/metrics/src/types/Metrics.ts b/packages/metrics/src/types/Metrics.ts
index c25653ca44..1d1874bdfe 100644
--- a/packages/metrics/src/types/Metrics.ts
+++ b/packages/metrics/src/types/Metrics.ts
@@ -2,6 +2,7 @@ import { Handler } from 'aws-lambda';
 import { LambdaInterface, AsyncHandler, SyncHandler } from '@aws-lambda-powertools/commons';
 import { ConfigServiceInterface } from '../config';
 import { MetricUnit } from './MetricUnit';
+import { MetricResolution } from './MetricResolution';
 
 type Dimensions = { [key: string]: string };
 
@@ -19,8 +20,8 @@ type EmfOutput = {
     Timestamp: number
     CloudWatchMetrics: {
       Namespace: string
-      Dimensions: [string[]]
-      Metrics: { Name: string; Unit: MetricUnit }[]
+      Dimensions: [string[]]   
+      Metrics: { Name: string; Unit: MetricUnit; StorageResolution: MetricResolution }[]
     }[]
   }
 };
@@ -60,6 +61,7 @@ type StoredMetric = {
   name: string
   unit: MetricUnit
   value: number | number[]
+  resolution: MetricResolution
 };
 
 type StoredMetrics = {
diff --git a/packages/metrics/src/types/index.ts b/packages/metrics/src/types/index.ts
index 44ff701f27..14416fbd33 100644
--- a/packages/metrics/src/types/index.ts
+++ b/packages/metrics/src/types/index.ts
@@ -1,2 +1,3 @@
 export * from './Metrics';
-export * from './MetricUnit';
\ No newline at end of file
+export * from './MetricUnit';
+export * from './MetricResolution';
\ No newline at end of file
diff --git a/packages/metrics/tests/unit/Metrics.test.ts b/packages/metrics/tests/unit/Metrics.test.ts
index 5f2bd02bf8..b55e32ef74 100644
--- a/packages/metrics/tests/unit/Metrics.test.ts
+++ b/packages/metrics/tests/unit/Metrics.test.ts
@@ -6,11 +6,13 @@
 
 import { ContextExamples as dummyContext, Events as dummyEvent, LambdaInterface } from '@aws-lambda-powertools/commons';
 import { Context, Callback } from 'aws-lambda';
-import { Metrics, MetricUnits } from '../../src/';
+
+import { Metrics, MetricUnits, MetricResolution } from '../../src/';
 
 const MAX_METRICS_SIZE = 100;
 const MAX_DIMENSION_COUNT = 29;
 const DEFAULT_NAMESPACE = 'default_namespace';
+const DEFAULT_METRIC_RESOLUTION = MetricResolution.Standard;
 
 const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
 
@@ -554,8 +556,8 @@ describe('Class: Metrics', () => {
       const serializedMetrics = metrics.serializeMetrics();
 
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics).toStrictEqual([
-        { Name: 'test_name', Unit: 'Count' },
-        { Name: 'test_name2', Unit: 'Count' },
+        { Name: 'test_name', Unit: 'Count', StorageResolution: DEFAULT_METRIC_RESOLUTION },
+        { Name: 'test_name2', Unit: 'Count', StorageResolution: DEFAULT_METRIC_RESOLUTION },
       ]);
       
       expect(serializedMetrics['test_name']).toBe(1);
@@ -563,6 +565,18 @@ describe('Class: Metrics', () => {
     });
   });
 
+  describe('Feature: Resolution of Metrics', ()=>{
+    test('Should use default metric resolution (STANDARD) if none is set',()=>{
+      const metrics = new Metrics();
+      metrics.addMetric('test_name', MetricUnits.Seconds, 10);
+      const serializedMetrics = metrics.serializeMetrics();
+
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(DEFAULT_METRIC_RESOLUTION);
+     
+    });
+   
+  });
+
   describe('Feature: Clearing Metrics ', () => {
     test('Clearing metrics should return empty', async () => {
       const metrics = new Metrics({ namespace: 'test' });
@@ -747,4 +761,44 @@ describe('Class: Metrics', () => {
       expect(loggedData._aws.CloudWatchMetrics[0].Namespace).toEqual(namespace);
     });
   });
+
+  describe('concept', ()=>{
+    test('metric DX type with const', ()=>{
+      const MetricResolutionConcept = {
+        Standard: 60,
+        High: 1
+      } as const;
+      type MetricResolutionConcept = typeof MetricResolutionConcept[keyof typeof MetricResolutionConcept];
+
+      const use = (resolution: MetricResolutionConcept):void => {
+        if (resolution === MetricResolutionConcept.Standard) expect(resolution).toBe(MetricResolution.Standard);
+        if (resolution === MetricResolution.High) expect(resolution).toBe(MetricResolutionConcept.High);
+      };
+
+      // prefered design of Metric Resolution, strcutural typing, compile time guidance 
+      use(MetricResolution.Standard);
+      use(60);
+      use(1);
+      // use(10); // Argument of type '10' is not assignable to parameter of type 'MetricResolutionConcept'.ts(2345)
+      //use(80); // Argument of type '10' is not assignable to parameter of type 'MetricResolutionConcept'.ts(2345)
+    });
+
+    test('metric DX type with enum', ()=>{
+      enum MetricResolutionEnum {
+        Standard = 60,
+        High = 1
+      }
+    
+      const use = (resolution: MetricResolutionEnum):void => {
+        if (resolution === MetricResolutionEnum.Standard) expect(resolution).toBe(MetricResolution.Standard);
+        if (resolution === MetricResolutionEnum.High) expect(resolution).toBe(MetricResolutionEnum.High);
+      };
+      use(MetricResolution.Standard);
+
+      // enum design, allows the following usage at compile time
+      use(10); // Argument of type '10' is assignable to parameter of type 'MetricResolutionEnum'
+      use(80); // Argument of type '10' is assignable to parameter of type 'MetricResolutionEnum'   
+    });
+    
+  });
 });
diff --git a/packages/metrics/tests/unit/middleware/middy.test.ts b/packages/metrics/tests/unit/middleware/middy.test.ts
index ad5a502120..d0f7177b4d 100644
--- a/packages/metrics/tests/unit/middleware/middy.test.ts
+++ b/packages/metrics/tests/unit/middleware/middy.test.ts
@@ -4,7 +4,7 @@
  * @group unit/metrics/middleware
  */
 
-import { Metrics, MetricUnits, logMetrics } from '../../../../metrics/src';
+import { Metrics, MetricUnits, logMetrics, MetricResolution } from '../../../../metrics/src';
 import middy from '@middy/core';
 import { ExtraOptions } from '../../../src/types';
 
@@ -178,7 +178,7 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [['service']],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count' }],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
               },
             ],
           },
@@ -215,7 +215,7 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [[ 'service', 'environment', 'aws_region', 'function_name' ]],
-                Metrics: [{ Name: 'ColdStart', Unit: 'Count' }],
+                Metrics: [{ Name: 'ColdStart', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
               },
             ],
           },
@@ -235,7 +235,7 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [[ 'service', 'environment', 'aws_region' ]],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count' }],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
               },
             ],
           },
@@ -270,7 +270,7 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [['service']],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count' }],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
               },
             ],
           },
@@ -305,7 +305,7 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [['service']],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count' }],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
               },
             ],
           },

From b3690c6ad8a862c22555dd97eddfee189127d087 Mon Sep 17 00:00:00 2001
From: niko-achilles <niko.achilles.kokkinos@gmail.com>
Date: Sat, 11 Mar 2023 17:06:36 +0200
Subject: [PATCH 2/8] feat(metrics): refactored addMetric function and new
 metric resolution tests (#1277)

---
 packages/metrics/src/Metrics.ts             |  4 ++--
 packages/metrics/tests/unit/Metrics.test.ts | 24 ++++++++++++++++++++-
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts
index a9ee392d62..0b3c3333a4 100644
--- a/packages/metrics/src/Metrics.ts
+++ b/packages/metrics/src/Metrics.ts
@@ -172,8 +172,8 @@ class Metrics extends Utility implements MetricsInterface {
    * @param value
    */
 
-  public addMetric(name: string, unit: MetricUnit, value: number, resolution?: MetricResolution): void {
-    this.storeMetric(name, unit, value, resolution ?? DEFAULT_METRIC_RESOLUTION );
+  public addMetric(name: string, unit: MetricUnit, value: number, resolution: MetricResolution = DEFAULT_METRIC_RESOLUTION): void {
+    this.storeMetric(name, unit, value, resolution);
     if (this.isSingleMetric) this.publishStoredMetrics();
   }
 
diff --git a/packages/metrics/tests/unit/Metrics.test.ts b/packages/metrics/tests/unit/Metrics.test.ts
index b55e32ef74..a4e7876d53 100644
--- a/packages/metrics/tests/unit/Metrics.test.ts
+++ b/packages/metrics/tests/unit/Metrics.test.ts
@@ -566,12 +566,34 @@ describe('Class: Metrics', () => {
   });
 
   describe('Feature: Resolution of Metrics', ()=>{
-    test('Should use default metric resolution (STANDARD) if none is set',()=>{
+    test('Should use default metric resolution `Standard, 60` if none is set',()=>{
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10);
       const serializedMetrics = metrics.serializeMetrics();
 
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(DEFAULT_METRIC_RESOLUTION);
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.Standard);
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(60);
+     
+    });
+
+    test('Should use metric resolution `Standard, 60` if `Standard` is set',()=>{
+      const metrics = new Metrics();
+      metrics.addMetric('test_name', MetricUnits.Seconds, 10, MetricResolution.Standard);
+      const serializedMetrics = metrics.serializeMetrics();
+
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.Standard);
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(60);
+     
+    });
+
+    test('Should use metric resolution `High, 1` if `High` is set',()=>{
+      const metrics = new Metrics();
+      metrics.addMetric('test_name', MetricUnits.Seconds, 10, MetricResolution.High);
+      const serializedMetrics = metrics.serializeMetrics();
+
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.High);
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(1);
      
     });
    

From a345831c6b7dbf37e907caff9490839c84e938c1 Mon Sep 17 00:00:00 2001
From: niko-achilles <niko.achilles.kokkinos@gmail.com>
Date: Sat, 11 Mar 2023 17:13:33 +0200
Subject: [PATCH 3/8] feat(metrics): raw values as metric resolution tests
 (#1277)

---
 packages/metrics/tests/unit/Metrics.test.ts | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/packages/metrics/tests/unit/Metrics.test.ts b/packages/metrics/tests/unit/Metrics.test.ts
index a4e7876d53..8b3a4cffbf 100644
--- a/packages/metrics/tests/unit/Metrics.test.ts
+++ b/packages/metrics/tests/unit/Metrics.test.ts
@@ -587,6 +587,26 @@ describe('Class: Metrics', () => {
      
     });
 
+    test('Should use metric resolution `Standard, 60` if `60` is set',()=>{
+      const metrics = new Metrics();
+      metrics.addMetric('test_name', MetricUnits.Seconds, 10, 60);
+      const serializedMetrics = metrics.serializeMetrics();
+
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.Standard);
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(60);
+     
+    });
+
+    test('Should use metric resolution `High, 1` if `1` is set',()=>{
+      const metrics = new Metrics();
+      metrics.addMetric('test_name', MetricUnits.Seconds, 10, 1);
+      const serializedMetrics = metrics.serializeMetrics();
+
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.High);
+      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(1);
+     
+    });
+
     test('Should use metric resolution `High, 1` if `High` is set',()=>{
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10, MetricResolution.High);

From dad0f2002842defdb6a679e528aa03c371fa7ca9 Mon Sep 17 00:00:00 2001
From: niko-achilles <niko.achilles.kokkinos@gmail.com>
Date: Sun, 12 Mar 2023 02:20:50 +0200
Subject: [PATCH 4/8] feat(metrics): use case Storage Resolution key when not
 set (#1277)

---
 packages/metrics/src/Metrics.ts               | 13 +++-
 packages/metrics/src/types/Metrics.ts         |  4 +-
 packages/metrics/tests/unit/Metrics.test.ts   | 29 +++-----
 .../tests/unit/middleware/middy.test.ts       | 74 +++++++++++++++++--
 4 files changed, 92 insertions(+), 28 deletions(-)

diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts
index 0b3c3333a4..21e8eb17a7 100644
--- a/packages/metrics/src/Metrics.ts
+++ b/packages/metrics/src/Metrics.ts
@@ -17,7 +17,6 @@ import {
 const MAX_METRICS_SIZE = 100;
 const MAX_DIMENSION_COUNT = 29;
 const DEFAULT_NAMESPACE = 'default_namespace';
-const DEFAULT_METRIC_RESOLUTION = MetricResolution.Standard; 
 
 /**
  * ## Intro
@@ -170,9 +169,10 @@ class Metrics extends Utility implements MetricsInterface {
    * @param name
    * @param unit
    * @param value
+   * @param resolution
    */
 
-  public addMetric(name: string, unit: MetricUnit, value: number, resolution: MetricResolution = DEFAULT_METRIC_RESOLUTION): void {
+  public addMetric(name: string, unit: MetricUnit, value: number, resolution?: MetricResolution): void {
     this.storeMetric(name, unit, value, resolution);
     if (this.isSingleMetric) this.publishStoredMetrics();
   }
@@ -322,11 +322,15 @@ class Metrics extends Utility implements MetricsInterface {
    * @returns {string}
    */
   public serializeMetrics(): EmfOutput {
-    const metricDefinitions = Object.values(this.storedMetrics).map((metricDefinition) => ({
+    const metricDefinitions = Object.values(this.storedMetrics).map((metricDefinition) => metricDefinition.resolution ? ({
       Name: metricDefinition.name,
       Unit: metricDefinition.unit,
       StorageResolution: metricDefinition.resolution
+    }): ({
+      Name: metricDefinition.name,
+      Unit: metricDefinition.unit
     }));
+    
     if (metricDefinitions.length === 0 && this.shouldThrowOnEmptyMetrics) {
       throw new RangeError('The number of metrics recorded must be higher than zero');
     }
@@ -483,7 +487,7 @@ class Metrics extends Utility implements MetricsInterface {
     }
   }
 
-  private storeMetric(name: string, unit: MetricUnit, value: number, resolution: MetricResolution): void {
+  private storeMetric(name: string, unit: MetricUnit, value: number, resolution?: MetricResolution): void {
     if (Object.keys(this.storedMetrics).length >= MAX_METRICS_SIZE) {
       this.publishStoredMetrics();
     }
@@ -495,6 +499,7 @@ class Metrics extends Utility implements MetricsInterface {
         name,
         resolution
       };
+      
     } else {
       const storedMetric = this.storedMetrics[name];
       if (!Array.isArray(storedMetric.value)) {
diff --git a/packages/metrics/src/types/Metrics.ts b/packages/metrics/src/types/Metrics.ts
index 1d1874bdfe..a4133c2faf 100644
--- a/packages/metrics/src/types/Metrics.ts
+++ b/packages/metrics/src/types/Metrics.ts
@@ -21,7 +21,7 @@ type EmfOutput = {
     CloudWatchMetrics: {
       Namespace: string
       Dimensions: [string[]]   
-      Metrics: { Name: string; Unit: MetricUnit; StorageResolution: MetricResolution }[]
+      Metrics: { Name: string; Unit: MetricUnit; StorageResolution?: MetricResolution }[]
     }[]
   }
 };
@@ -61,7 +61,7 @@ type StoredMetric = {
   name: string
   unit: MetricUnit
   value: number | number[]
-  resolution: MetricResolution
+  resolution?: MetricResolution
 };
 
 type StoredMetrics = {
diff --git a/packages/metrics/tests/unit/Metrics.test.ts b/packages/metrics/tests/unit/Metrics.test.ts
index 8b3a4cffbf..8c8b5078fa 100644
--- a/packages/metrics/tests/unit/Metrics.test.ts
+++ b/packages/metrics/tests/unit/Metrics.test.ts
@@ -12,7 +12,6 @@ import { Metrics, MetricUnits, MetricResolution } from '../../src/';
 const MAX_METRICS_SIZE = 100;
 const MAX_DIMENSION_COUNT = 29;
 const DEFAULT_NAMESPACE = 'default_namespace';
-const DEFAULT_METRIC_RESOLUTION = MetricResolution.Standard;
 
 const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
 
@@ -556,8 +555,8 @@ describe('Class: Metrics', () => {
       const serializedMetrics = metrics.serializeMetrics();
 
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics).toStrictEqual([
-        { Name: 'test_name', Unit: 'Count', StorageResolution: DEFAULT_METRIC_RESOLUTION },
-        { Name: 'test_name2', Unit: 'Count', StorageResolution: DEFAULT_METRIC_RESOLUTION },
+        { Name: 'test_name', Unit: 'Count' },
+        { Name: 'test_name2', Unit: 'Count' },
       ]);
       
       expect(serializedMetrics['test_name']).toBe(1);
@@ -566,57 +565,53 @@ describe('Class: Metrics', () => {
   });
 
   describe('Feature: Resolution of Metrics', ()=>{
-    test('Should use default metric resolution `Standard, 60` if none is set',()=>{
+    test('Should serialized metrics in EMF format not contain StorageResolution as key if none is set',()=>{
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10);
       const serializedMetrics = metrics.serializeMetrics();
 
-      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(DEFAULT_METRIC_RESOLUTION);
-      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.Standard);
-      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(60);
+      expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).not.toContain('StorageResolution');
+      expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).toContain('Name');
+      expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).toContain('Unit');
      
     });
 
-    test('Should use metric resolution `Standard, 60` if `Standard` is set',()=>{
+    test('Should be StorageResolution 60 if MetricResolution is set to `Standard`',()=>{
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10, MetricResolution.Standard);
       const serializedMetrics = metrics.serializeMetrics();
 
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.Standard);
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(60);
-     
     });
 
-    test('Should use metric resolution `Standard, 60` if `60` is set',()=>{
+    test('Should be StorageResolution 60 if MetricResolution is set to `60`',()=>{
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10, 60);
       const serializedMetrics = metrics.serializeMetrics();
 
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.Standard);
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(60);
-     
     });
 
-    test('Should use metric resolution `High, 1` if `1` is set',()=>{
+    test('Should be StorageResolution 1 if MetricResolution is set to `High`',()=>{
       const metrics = new Metrics();
-      metrics.addMetric('test_name', MetricUnits.Seconds, 10, 1);
+      metrics.addMetric('test_name', MetricUnits.Seconds, 10, MetricResolution.High);
       const serializedMetrics = metrics.serializeMetrics();
 
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.High);
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(1);
-     
     });
 
-    test('Should use metric resolution `High, 1` if `High` is set',()=>{
+    test('Should be StorageResolution 1 if MetricResolution is set to `1`',()=>{
       const metrics = new Metrics();
-      metrics.addMetric('test_name', MetricUnits.Seconds, 10, MetricResolution.High);
+      metrics.addMetric('test_name', MetricUnits.Seconds, 10, 1);
       const serializedMetrics = metrics.serializeMetrics();
 
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.High);
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(1);
      
     });
-   
   });
 
   describe('Feature: Clearing Metrics ', () => {
diff --git a/packages/metrics/tests/unit/middleware/middy.test.ts b/packages/metrics/tests/unit/middleware/middy.test.ts
index d0f7177b4d..8db2924275 100644
--- a/packages/metrics/tests/unit/middleware/middy.test.ts
+++ b/packages/metrics/tests/unit/middleware/middy.test.ts
@@ -178,7 +178,7 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [['service']],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count' }],
               },
             ],
           },
@@ -215,7 +215,7 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [[ 'service', 'environment', 'aws_region', 'function_name' ]],
-                Metrics: [{ Name: 'ColdStart', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
+                Metrics: [{ Name: 'ColdStart', Unit: 'Count' }],
               },
             ],
           },
@@ -235,7 +235,7 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [[ 'service', 'environment', 'aws_region' ]],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count' }],
               },
             ],
           },
@@ -270,7 +270,7 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [['service']],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count' }],
               },
             ],
           },
@@ -305,7 +305,71 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [['service']],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: MetricResolution.Standard }],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count' }],
+              },
+            ],
+          },
+          service: 'orders',
+          successfulBooking: 1,
+        })
+      );
+    });
+  });
+  describe('Feature: Resolution of Metrics', ()=>{
+    test('Should use metric resolution `Standard, 60` if `Standard` is set', async () => {
+      // Prepare
+      const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' });
+
+      const lambdaHandler = (): void => {
+        metrics.addMetric('successfulBooking', MetricUnits.Count, 1, MetricResolution.Standard);
+      };
+
+      const handler = middy(lambdaHandler).use(logMetrics(metrics));
+
+      // Act
+      await handler(dummyEvent, dummyContext, () => console.log('Lambda invoked!'));
+
+      // Assess
+      expect(console.log).toHaveBeenCalledWith(
+        JSON.stringify({
+          _aws: {
+            Timestamp: 1466424490000,
+            CloudWatchMetrics: [
+              {
+                Namespace: 'serverlessAirline',
+                Dimensions: [['service']],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: 60 }],
+              },
+            ],
+          },
+          service: 'orders',
+          successfulBooking: 1,
+        })
+      );
+    });
+    test('Should use metric resolution `High, 1` if `High` is set', async () => {
+      // Prepare
+      const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' });
+
+      const lambdaHandler = (): void => {
+        metrics.addMetric('successfulBooking', MetricUnits.Count, 1, MetricResolution.High);
+      };
+
+      const handler = middy(lambdaHandler).use(logMetrics(metrics));
+
+      // Act
+      await handler(dummyEvent, dummyContext, () => console.log('Lambda invoked!'));
+
+      // Assess
+      expect(console.log).toHaveBeenCalledWith(
+        JSON.stringify({
+          _aws: {
+            Timestamp: 1466424490000,
+            CloudWatchMetrics: [
+              {
+                Namespace: 'serverlessAirline',
+                Dimensions: [['service']],
+                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: 1 }],
               },
             ],
           },

From 7a25f2f768ea814bb449920832557204339730ba Mon Sep 17 00:00:00 2001
From: niko-achilles <niko.achilles.kokkinos@gmail.com>
Date: Tue, 14 Mar 2023 01:28:01 +0200
Subject: [PATCH 5/8] feat(metrics): apply styling

---
 packages/metrics/src/Metrics.ts               | 17 ++++++++---
 packages/metrics/src/MetricsInterface.ts      | 10 +++++--
 packages/metrics/src/types/Metrics.ts         |  6 +++-
 packages/metrics/tests/unit/Metrics.test.ts   |  6 ++--
 .../tests/unit/middleware/middy.test.ts       | 28 ++++++++++++++-----
 5 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts
index 21e8eb17a7..075f77d5b4 100644
--- a/packages/metrics/src/Metrics.ts
+++ b/packages/metrics/src/Metrics.ts
@@ -11,7 +11,7 @@ import {
   ExtraOptions,
   MetricUnit,
   MetricUnits,
-  MetricResolution
+  MetricResolution,
 } from './types';
 
 const MAX_METRICS_SIZE = 100;
@@ -487,7 +487,12 @@ class Metrics extends Utility implements MetricsInterface {
     }
   }
 
-  private storeMetric(name: string, unit: MetricUnit, value: number, resolution?: MetricResolution): void {
+  private storeMetric(
+    name: string,
+    unit: MetricUnit,
+    value: number,
+    resolution?: MetricResolution,
+  ): void {    
     if (Object.keys(this.storedMetrics).length >= MAX_METRICS_SIZE) {
       this.publishStoredMetrics();
     }
@@ -497,7 +502,7 @@ class Metrics extends Utility implements MetricsInterface {
         unit,
         value,
         name,
-        resolution
+        resolution,      
       };
       
     } else {
@@ -511,4 +516,8 @@ class Metrics extends Utility implements MetricsInterface {
 
 }
 
-export { Metrics, MetricUnits, MetricResolution };
+export {
+  Metrics,
+  MetricUnits,
+  MetricResolution,
+};
\ No newline at end of file
diff --git a/packages/metrics/src/MetricsInterface.ts b/packages/metrics/src/MetricsInterface.ts
index f7ad653b43..bb8dea45b7 100644
--- a/packages/metrics/src/MetricsInterface.ts
+++ b/packages/metrics/src/MetricsInterface.ts
@@ -1,6 +1,12 @@
 import { Metrics } from './Metrics';
-import { MetricUnit, MetricResolution, EmfOutput, HandlerMethodDecorator, Dimensions, MetricsOptions } from './types';
-
+import {
+  MetricUnit,
+  MetricResolution,
+  EmfOutput,
+  HandlerMethodDecorator,
+  Dimensions,
+  MetricsOptions
+} from './types';
 interface MetricsInterface {
   addDimension(name: string, value: string): void
   addDimensions(dimensions: {[key: string]: string}): void
diff --git a/packages/metrics/src/types/Metrics.ts b/packages/metrics/src/types/Metrics.ts
index a4133c2faf..2c856c84ab 100644
--- a/packages/metrics/src/types/Metrics.ts
+++ b/packages/metrics/src/types/Metrics.ts
@@ -21,7 +21,11 @@ type EmfOutput = {
     CloudWatchMetrics: {
       Namespace: string
       Dimensions: [string[]]   
-      Metrics: { Name: string; Unit: MetricUnit; StorageResolution?: MetricResolution }[]
+      Metrics: {
+        Name: string
+        Unit: MetricUnit
+        StorageResolution?: MetricResolution
+      }[]    
     }[]
   }
 };
diff --git a/packages/metrics/tests/unit/Metrics.test.ts b/packages/metrics/tests/unit/Metrics.test.ts
index 8c8b5078fa..a826cef583 100644
--- a/packages/metrics/tests/unit/Metrics.test.ts
+++ b/packages/metrics/tests/unit/Metrics.test.ts
@@ -565,7 +565,8 @@ describe('Class: Metrics', () => {
   });
 
   describe('Feature: Resolution of Metrics', ()=>{
-    test('Should serialized metrics in EMF format not contain StorageResolution as key if none is set',()=>{
+
+    test('serialized metrics in EMF format should not contain `StorageResolution` as key if none is set', () => {
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10);
       const serializedMetrics = metrics.serializeMetrics();
@@ -575,8 +576,7 @@ describe('Class: Metrics', () => {
       expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).toContain('Unit');
      
     });
-
-    test('Should be StorageResolution 60 if MetricResolution is set to `Standard`',()=>{
+    test('should set StorageResolution 60 if MetricResolution is set to `Standard`', () => {
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10, MetricResolution.Standard);
       const serializedMetrics = metrics.serializeMetrics();
diff --git a/packages/metrics/tests/unit/middleware/middy.test.ts b/packages/metrics/tests/unit/middleware/middy.test.ts
index 8db2924275..464b4a660a 100644
--- a/packages/metrics/tests/unit/middleware/middy.test.ts
+++ b/packages/metrics/tests/unit/middleware/middy.test.ts
@@ -4,8 +4,12 @@
  * @group unit/metrics/middleware
  */
 
-import { Metrics, MetricUnits, logMetrics, MetricResolution } from '../../../../metrics/src';
-import middy from '@middy/core';
+import {
+  Metrics,
+  MetricUnits,
+  logMetrics,
+  MetricResolution
+} from '../../../../metrics/src';import middy from '@middy/core';
 import { ExtraOptions } from '../../../src/types';
 
 const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
@@ -315,8 +319,9 @@ describe('Middy middleware', () => {
       );
     });
   });
-  describe('Feature: Resolution of Metrics', ()=>{
-    test('Should use metric resolution `Standard, 60` if `Standard` is set', async () => {
+  describe('Metrics resolution', () => {
+
+    test('should use metric resolution `Standard, 60` if `Standard` is set', async () => {
       // Prepare
       const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' });
 
@@ -338,7 +343,11 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [['service']],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: 60 }],
+                Metrics: [{
+                  Name: 'successfulBooking',
+                  Unit: 'Count',
+                  StorageResolution: 60,
+                }],              
               },
             ],
           },
@@ -347,7 +356,8 @@ describe('Middy middleware', () => {
         })
       );
     });
-    test('Should use metric resolution `High, 1` if `High` is set', async () => {
+
+    test('should use metric resolution `High, 1` if `High` is set', async () => {
       // Prepare
       const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' });
 
@@ -369,7 +379,11 @@ describe('Middy middleware', () => {
               {
                 Namespace: 'serverlessAirline',
                 Dimensions: [['service']],
-                Metrics: [{ Name: 'successfulBooking', Unit: 'Count', StorageResolution: 1 }],
+                Metrics: [{
+                  Name: 'successfulBooking',
+                  Unit: 'Count',
+                  StorageResolution: 1
+                }],              
               },
             ],
           },

From b80798ff0bd409267450b956174d5602232c2aae Mon Sep 17 00:00:00 2001
From: niko-achilles <niko.achilles.kokkinos@gmail.com>
Date: Tue, 14 Mar 2023 22:46:14 +0100
Subject: [PATCH 6/8] feat(metrics): remove learning concept as const

---
 packages/metrics/tests/unit/Metrics.test.ts | 40 ---------------------
 1 file changed, 40 deletions(-)

diff --git a/packages/metrics/tests/unit/Metrics.test.ts b/packages/metrics/tests/unit/Metrics.test.ts
index a826cef583..725bfb8967 100644
--- a/packages/metrics/tests/unit/Metrics.test.ts
+++ b/packages/metrics/tests/unit/Metrics.test.ts
@@ -798,44 +798,4 @@ describe('Class: Metrics', () => {
       expect(loggedData._aws.CloudWatchMetrics[0].Namespace).toEqual(namespace);
     });
   });
-
-  describe('concept', ()=>{
-    test('metric DX type with const', ()=>{
-      const MetricResolutionConcept = {
-        Standard: 60,
-        High: 1
-      } as const;
-      type MetricResolutionConcept = typeof MetricResolutionConcept[keyof typeof MetricResolutionConcept];
-
-      const use = (resolution: MetricResolutionConcept):void => {
-        if (resolution === MetricResolutionConcept.Standard) expect(resolution).toBe(MetricResolution.Standard);
-        if (resolution === MetricResolution.High) expect(resolution).toBe(MetricResolutionConcept.High);
-      };
-
-      // prefered design of Metric Resolution, strcutural typing, compile time guidance 
-      use(MetricResolution.Standard);
-      use(60);
-      use(1);
-      // use(10); // Argument of type '10' is not assignable to parameter of type 'MetricResolutionConcept'.ts(2345)
-      //use(80); // Argument of type '10' is not assignable to parameter of type 'MetricResolutionConcept'.ts(2345)
-    });
-
-    test('metric DX type with enum', ()=>{
-      enum MetricResolutionEnum {
-        Standard = 60,
-        High = 1
-      }
-    
-      const use = (resolution: MetricResolutionEnum):void => {
-        if (resolution === MetricResolutionEnum.Standard) expect(resolution).toBe(MetricResolution.Standard);
-        if (resolution === MetricResolutionEnum.High) expect(resolution).toBe(MetricResolutionEnum.High);
-      };
-      use(MetricResolution.Standard);
-
-      // enum design, allows the following usage at compile time
-      use(10); // Argument of type '10' is assignable to parameter of type 'MetricResolutionEnum'
-      use(80); // Argument of type '10' is assignable to parameter of type 'MetricResolutionEnum'   
-    });
-    
-  });
 });

From fc379f9d5df06fa2a7d6243d1042108f702db28a Mon Sep 17 00:00:00 2001
From: niko-achilles <niko.achilles.kokkinos@gmail.com>
Date: Thu, 16 Mar 2023 05:30:08 +0100
Subject: [PATCH 7/8] feat(metrics): refactoring cost improvement website docs
 and code comments

---
 docs/core/metrics.md                          | 21 +++++-
 .../metrics/addHighResolutionMetric.ts        |  7 ++
 docs/snippets/metrics/basicUsage.ts           |  2 +-
 docs/snippets/metrics/tsconfig.json           | 19 +++++
 packages/metrics/src/Metrics.ts               | 72 ++++++++++++++-----
 packages/metrics/src/types/Metrics.ts         | 16 +++--
 packages/metrics/tests/unit/Metrics.test.ts   | 21 +++---
 .../tests/unit/middleware/middy.test.ts       |  5 +-
 8 files changed, 124 insertions(+), 39 deletions(-)
 create mode 100644 docs/snippets/metrics/addHighResolutionMetric.ts
 create mode 100644 docs/snippets/metrics/tsconfig.json

diff --git a/docs/core/metrics.md b/docs/core/metrics.md
index 12f74854bd..8cd17c0a36 100644
--- a/docs/core/metrics.md
+++ b/docs/core/metrics.md
@@ -27,6 +27,9 @@ If you're new to Amazon CloudWatch, there are two terminologies you must be awar
 
 * **Namespace**. It's the highest level container that will group multiple metrics from multiple services for a given application, for example `ServerlessEcommerce`.
 * **Dimensions**. Metrics metadata in key-value format. They help you slice and dice metrics visualization, for example `ColdStart` metric by Payment `service`.
+* **Metric**. It's the name of the metric, for example: SuccessfulBooking or UpdatedBooking.
+* **Unit**. It's a value representing the unit of measure for the corresponding metric, for example: Count or Seconds.
+* **Resolution**. It's a value representing the storage resolution for the corresponding metric. Metrics can be either Standard or High resolution. Read more [here](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Resolution_definition).
 
 <figure>
   <img src="../../media/metrics_terminology.png" />
@@ -117,7 +120,23 @@ You can create metrics using the `addMetric` method, and you can create dimensio
     CloudWatch EMF supports a max of 100 metrics per batch. Metrics will automatically propagate all the metrics when adding the 100th metric. Subsequent metrics, e.g. 101th, will be aggregated into a new EMF object, for your convenience.
 
 !!! warning "Do not create metrics or dimensions outside the handler"
-    Metrics or dimensions added in the global scope will only be added during cold start. Disregard if that's the intended behaviour.
+    Metrics or dimensions added in the global scope will only be added during cold start. Disregard if that's the intended behavior.
+
+### Adding high-resolution metrics
+
+You can create [high-resolution metrics](https://aws.amazon.com/about-aws/whats-new/2023/02/amazon-cloudwatch-high-resolution-metric-extraction-structured-logs/) passing `resolution` as parameter to `addMetric`. 
+
+!!! tip "When is it useful?"
+    High-resolution metrics are data with a granularity of one second and are very useful in several situations such as telemetry, time series, real-time incident management, and others.
+
+=== "Metrics with high resolution"
+
+    ```typescript hl_lines="6"
+    --8<-- "docs/snippets/metrics/addHighResolutionMetric.ts"
+    ```
+
+!!! tip "Autocomplete Metric Resolutions"
+    Use the `MetricResolution` type to easily find a supported metric resolution by CloudWatch. Alternatively, you can pass the allowed values of 1 or 60 as an integer.
 
 ### Adding multi-value metrics
 
diff --git a/docs/snippets/metrics/addHighResolutionMetric.ts b/docs/snippets/metrics/addHighResolutionMetric.ts
new file mode 100644
index 0000000000..0e44bcbcbb
--- /dev/null
+++ b/docs/snippets/metrics/addHighResolutionMetric.ts
@@ -0,0 +1,7 @@
+import { Metrics, MetricUnits, MetricResolution } from '@aws-lambda-powertools/metrics';
+
+const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' });
+
+export const handler = async (_event: unknown, _context: unknown): Promise<void> => {
+  metrics.addMetric('successfulBooking', MetricUnits.Count, 1, MetricResolution.High);
+};
diff --git a/docs/snippets/metrics/basicUsage.ts b/docs/snippets/metrics/basicUsage.ts
index 15388d2c82..ccd8606a01 100644
--- a/docs/snippets/metrics/basicUsage.ts
+++ b/docs/snippets/metrics/basicUsage.ts
@@ -2,6 +2,6 @@ import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics';
 
 const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' });
 
-export const handler = async (_event, _context): Promise<void> => {
+export const handler = async (_event: unknown, _context: unknown): Promise<void> => {
   metrics.addMetric('successfulBooking', MetricUnits.Count, 1);
 };
\ No newline at end of file
diff --git a/docs/snippets/metrics/tsconfig.json b/docs/snippets/metrics/tsconfig.json
new file mode 100644
index 0000000000..40951b4161
--- /dev/null
+++ b/docs/snippets/metrics/tsconfig.json
@@ -0,0 +1,19 @@
+{
+  "compilerOptions": {
+    "noEmit": true,
+    "strict": true,
+    "noImplicitAny": true,
+    "experimentalDecorators": true,
+    "moduleResolution": "node",
+    "skipLibCheck": true,
+    "pretty": true,
+    "resolveJsonModule": true,
+    "baseUrl": ".",
+    "paths": {
+      "@aws-lambda-powertools/metrics": ["../../../packages/metrics/src"]
+    }
+  },
+  "exclude": ["./node_modules"],
+  "lib": ["ES2020"],
+  "types": ["node"]
+}
diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts
index 075f77d5b4..35b38f8611 100644
--- a/packages/metrics/src/Metrics.ts
+++ b/packages/metrics/src/Metrics.ts
@@ -12,6 +12,8 @@ import {
   MetricUnit,
   MetricUnits,
   MetricResolution,
+  MetricDefinition,
+  StoredMetric,
 } from './types';
 
 const MAX_METRICS_SIZE = 100;
@@ -166,13 +168,32 @@ class Metrics extends Utility implements MetricsInterface {
 
   /**
    * Add a metric to the metrics buffer.
-   * @param name
-   * @param unit
-   * @param value
-   * @param resolution
+   *
+   * @example 
+   *
+   * Add Metric using MetricUnit Enum supported by Cloudwatch
+   * 
+   * ```ts
+   * metrics.addMetric('successfulBooking', MetricUnits.Count, 1);
+   * ```
+   * 
+   * @example 
+   * 
+   * Add Metric using MetricResolution type with resolutions High or Standard supported by cloudwatch 
+   * 
+   * ```ts
+   * metrics.addMetric('successfulBooking', MetricUnits.Count, 1, MetricResolution.High);
+   * ```
+   * 
+   * @param name - The metric name 
+   * @param unit - The metric unit
+   * @param value - The metric value
+   * @param resolution - The metric resolution
+   * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Resolution_definition Amazon Cloudwatch Concepts Documentation  
+   * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Specification.html#CloudWatch_Embedded_Metric_Format_Specification_structure_metricdefinition Metric Definition of Embedded Metric Format Specification
    */
 
-  public addMetric(name: string, unit: MetricUnit, value: number, resolution?: MetricResolution): void {
+  public addMetric(name: string, unit: MetricUnit, value: number, resolution: MetricResolution = MetricResolution.Standard): void {
     this.storeMetric(name, unit, value, resolution);
     if (this.isSingleMetric) this.publishStoredMetrics();
   }
@@ -317,19 +338,28 @@ class Metrics extends Utility implements MetricsInterface {
   }
 
   /**
-   * Function to create the right object compliant with Cloudwatch EMF (Event Metric Format).
+   * Function to create the right object compliant with Cloudwatch EMF (Embedded Metric Format).
+   * 
+   * 
+   * @returns metrics as JSON object compliant EMF Schema Specification
    * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Specification.html for more details
-   * @returns {string}
    */
   public serializeMetrics(): EmfOutput {
-    const metricDefinitions = Object.values(this.storedMetrics).map((metricDefinition) => metricDefinition.resolution ? ({
-      Name: metricDefinition.name,
-      Unit: metricDefinition.unit,
-      StorageResolution: metricDefinition.resolution
-    }): ({
-      Name: metricDefinition.name,
-      Unit: metricDefinition.unit
-    }));
+    // For high-resolution metrics, add StorageResolution property
+    // Example: [ { "Name": "metric_name", "Unit": "Count", "StorageResolution": 1 } ]
+
+    // For standard resolution metrics, don't add StorageResolution property to avoid unnecessary ingestion of data into cloudwatch
+    // Example: [ { "Name": "metric_name", "Unit": "Count"} ]
+    const metricDefinitions: MetricDefinition[] = Object.values(this.storedMetrics).map((metricDefinition) => 
+      this.isHigh(metricDefinition['resolution']) 
+        ? ({
+          Name: metricDefinition.name,
+          Unit: metricDefinition.unit,
+          StorageResolution: metricDefinition.resolution
+        }): ({
+          Name: metricDefinition.name,
+          Unit: metricDefinition.unit,
+        }));
     
     if (metricDefinitions.length === 0 && this.shouldThrowOnEmptyMetrics) {
       throw new RangeError('The number of metrics recorded must be higher than zero');
@@ -437,6 +467,10 @@ class Metrics extends Utility implements MetricsInterface {
     return <EnvironmentVariablesService> this.envVarsService;
   }
 
+  private isHigh(resolution: StoredMetric['resolution']): resolution is 1 {
+    return resolution === MetricResolution.High;
+  }
+
   private isNewMetric(name: string, unit: MetricUnit): boolean {
     if (this.storedMetrics[name]){
       // Inconsistent units indicates a bug or typos and we want to flag this to users early
@@ -491,7 +525,7 @@ class Metrics extends Utility implements MetricsInterface {
     name: string,
     unit: MetricUnit,
     value: number,
-    resolution?: MetricResolution,
+    resolution: MetricResolution,
   ): void {    
     if (Object.keys(this.storedMetrics).length >= MAX_METRICS_SIZE) {
       this.publishStoredMetrics();
@@ -501,10 +535,10 @@ class Metrics extends Utility implements MetricsInterface {
       this.storedMetrics[name] = {
         unit,
         value,
-        name,
-        resolution,      
+        name, 
+        resolution    
       };
-      
+       
     } else {
       const storedMetric = this.storedMetrics[name];
       if (!Array.isArray(storedMetric.value)) {
diff --git a/packages/metrics/src/types/Metrics.ts b/packages/metrics/src/types/Metrics.ts
index 2c856c84ab..8c0c12f541 100644
--- a/packages/metrics/src/types/Metrics.ts
+++ b/packages/metrics/src/types/Metrics.ts
@@ -21,11 +21,7 @@ type EmfOutput = {
     CloudWatchMetrics: {
       Namespace: string
       Dimensions: [string[]]   
-      Metrics: {
-        Name: string
-        Unit: MetricUnit
-        StorageResolution?: MetricResolution
-      }[]    
+      Metrics: MetricDefinition[]    
     }[]
   }
 };
@@ -65,11 +61,17 @@ type StoredMetric = {
   name: string
   unit: MetricUnit
   value: number | number[]
-  resolution?: MetricResolution
+  resolution: MetricResolution
 };
 
 type StoredMetrics = {
   [key: string]: StoredMetric
 };
 
-export { MetricsOptions, Dimensions, EmfOutput, HandlerMethodDecorator, ExtraOptions, StoredMetrics };
+type MetricDefinition = {
+  Name: string
+  Unit: MetricUnit
+  StorageResolution?: MetricResolution
+}; 
+
+export { MetricsOptions, Dimensions, EmfOutput, HandlerMethodDecorator, ExtraOptions, StoredMetrics, StoredMetric, MetricDefinition };
diff --git a/packages/metrics/tests/unit/Metrics.test.ts b/packages/metrics/tests/unit/Metrics.test.ts
index 725bfb8967..a3960b9635 100644
--- a/packages/metrics/tests/unit/Metrics.test.ts
+++ b/packages/metrics/tests/unit/Metrics.test.ts
@@ -576,25 +576,30 @@ describe('Class: Metrics', () => {
       expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).toContain('Unit');
      
     });
-    test('should set StorageResolution 60 if MetricResolution is set to `Standard`', () => {
+    test('serialized metrics in EMF format should not contain `StorageResolution` as key if `Standard` is set', () => {
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10, MetricResolution.Standard);
       const serializedMetrics = metrics.serializeMetrics();
 
-      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.Standard);
-      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(60);
+      // expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.Standard);
+      // expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(60);
+
+      expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).not.toContain('StorageResolution');
+      expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).toContain('Name');
+      expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).toContain('Unit');
     });
 
-    test('Should be StorageResolution 60 if MetricResolution is set to `60`',()=>{
+    test('serialized metrics in EMF format should not contain `StorageResolution` as key if `60` is set',()=>{
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10, 60);
       const serializedMetrics = metrics.serializeMetrics();
 
-      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(MetricResolution.Standard);
-      expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(60);
+      expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).not.toContain('StorageResolution');
+      expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).toContain('Name');
+      expect(Object.keys(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0])).toContain('Unit');
     });
 
-    test('Should be StorageResolution 1 if MetricResolution is set to `High`',()=>{
+    test('Should be StorageResolution `1` if MetricResolution is set to `High`',()=>{
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10, MetricResolution.High);
       const serializedMetrics = metrics.serializeMetrics();
@@ -603,7 +608,7 @@ describe('Class: Metrics', () => {
       expect(serializedMetrics._aws.CloudWatchMetrics[0].Metrics[0].StorageResolution).toBe(1);
     });
 
-    test('Should be StorageResolution 1 if MetricResolution is set to `1`',()=>{
+    test('Should be StorageResolution `1` if MetricResolution is set to `1`',()=>{
       const metrics = new Metrics();
       metrics.addMetric('test_name', MetricUnits.Seconds, 10, 1);
       const serializedMetrics = metrics.serializeMetrics();
diff --git a/packages/metrics/tests/unit/middleware/middy.test.ts b/packages/metrics/tests/unit/middleware/middy.test.ts
index 464b4a660a..1ee25e79d6 100644
--- a/packages/metrics/tests/unit/middleware/middy.test.ts
+++ b/packages/metrics/tests/unit/middleware/middy.test.ts
@@ -321,7 +321,7 @@ describe('Middy middleware', () => {
   });
   describe('Metrics resolution', () => {
 
-    test('should use metric resolution `Standard, 60` if `Standard` is set', async () => {
+    test('serialized metrics in EMF format should not contain `StorageResolution` as key if `60` is set', async () => {
       // Prepare
       const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' });
 
@@ -346,7 +346,6 @@ describe('Middy middleware', () => {
                 Metrics: [{
                   Name: 'successfulBooking',
                   Unit: 'Count',
-                  StorageResolution: 60,
                 }],              
               },
             ],
@@ -357,7 +356,7 @@ describe('Middy middleware', () => {
       );
     });
 
-    test('should use metric resolution `High, 1` if `High` is set', async () => {
+    test('Should be StorageResolution `1` if MetricResolution is set to `High`', async () => {
       // Prepare
       const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' });
 

From 4b14bcb4403335d0cd9d9f07991e8657b8e73c2e Mon Sep 17 00:00:00 2001
From: niko-achilles <niko.achilles.kokkinos@gmail.com>
Date: Thu, 16 Mar 2023 17:12:56 +0100
Subject: [PATCH 8/8] feat(metrics): improve isHigh typeguard, remove tsconfig
 from metrics snippet

---
 docs/snippets/metrics/tsconfig.json | 19 -------------------
 packages/metrics/src/Metrics.ts     |  2 +-
 2 files changed, 1 insertion(+), 20 deletions(-)
 delete mode 100644 docs/snippets/metrics/tsconfig.json

diff --git a/docs/snippets/metrics/tsconfig.json b/docs/snippets/metrics/tsconfig.json
deleted file mode 100644
index 40951b4161..0000000000
--- a/docs/snippets/metrics/tsconfig.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "compilerOptions": {
-    "noEmit": true,
-    "strict": true,
-    "noImplicitAny": true,
-    "experimentalDecorators": true,
-    "moduleResolution": "node",
-    "skipLibCheck": true,
-    "pretty": true,
-    "resolveJsonModule": true,
-    "baseUrl": ".",
-    "paths": {
-      "@aws-lambda-powertools/metrics": ["../../../packages/metrics/src"]
-    }
-  },
-  "exclude": ["./node_modules"],
-  "lib": ["ES2020"],
-  "types": ["node"]
-}
diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts
index 35b38f8611..12bfc85451 100644
--- a/packages/metrics/src/Metrics.ts
+++ b/packages/metrics/src/Metrics.ts
@@ -467,7 +467,7 @@ class Metrics extends Utility implements MetricsInterface {
     return <EnvironmentVariablesService> this.envVarsService;
   }
 
-  private isHigh(resolution: StoredMetric['resolution']): resolution is 1 {
+  private isHigh(resolution: StoredMetric['resolution']): resolution is typeof MetricResolution['High'] {
     return resolution === MetricResolution.High;
   }