From 4cc840b4e8a6dabf8da9238aa4f3dc55478dda6b Mon Sep 17 00:00:00 2001 From: Niek Palm Date: Thu, 3 Jul 2025 22:42:27 +0200 Subject: [PATCH 1/3] feat: Add release version to lambda conext for logging (#14) * fix: add lambda version to context logging * release tests * release tests * fix: Add lambda version to log context * fix: Add lambda version to log context * fix: Add lambda version to log context * fix: Add lambda version to log context * fix: Add lambda version to log context * feat: Add lambda version to log context --- .github/workflows/release.yml | 3 +- .release-please-config.json | 34 ++++++++ .release-please-manifest.json | 3 + .../aws-powertools-util/src/logger/index.ts | 18 +++++ .../src/logger/logger.test.ts | 79 ++++++++++++++++++- 5 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 .release-please-config.json create mode 100644 .release-please-manifest.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d70f0a60a7..895410453a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,7 +40,8 @@ jobs: uses: googleapis/release-please-action@a02a34c4d625f9be7cb89156071d8567266a2445 # v4.2.0 with: target-branch: ${{ steps.branch.outputs.name }} - release-type: terraform-module + manifest-file: .release-please-manifest.json + config-file: .release-please-config.json token: ${{ steps.token.outputs.token }} - name: Attest if: ${{ steps.release.outputs.releases_created == 'true' }} diff --git a/.release-please-config.json b/.release-please-config.json new file mode 100644 index 0000000000..7c55680405 --- /dev/null +++ b/.release-please-config.json @@ -0,0 +1,34 @@ +{ + "release-type": "simple", + "packages": { + ".": { + "extra-files": [ + { + "type": "json", + "path": "lambdas/functions/ami-housekeeper/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "lambdas/functions/control-plane/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "lambdas/functions/gh-agent-syncer/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "lambdas/functions/termination-watcher/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "lambdas/functions/webhook/package.json", + "jsonpath": "$.version" + } + ] + } + } +} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000000..2f0a9c430f --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "6.6.0" +} diff --git a/lambdas/libs/aws-powertools-util/src/logger/index.ts b/lambdas/libs/aws-powertools-util/src/logger/index.ts index 195b552a74..f3fdbe3c6e 100644 --- a/lambdas/libs/aws-powertools-util/src/logger/index.ts +++ b/lambdas/libs/aws-powertools-util/src/logger/index.ts @@ -1,17 +1,34 @@ import { Logger } from '@aws-lambda-powertools/logger'; import { Context } from 'aws-lambda'; +import * as fs from 'fs'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; const childLoggers: Logger[] = []; +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + const defaultValues = { region: process.env.AWS_REGION, environment: process.env.ENVIRONMENT || 'N/A', }; +function getReleaseVersion(): string { + let version = 'unknown'; + try { + const packageFilePath = path.resolve(__dirname, 'package.json'); + version = JSON.parse(fs.readFileSync(packageFilePath, 'utf-8')).version || 'unknown'; + } catch (error) { + logger.debug(`Failed to read package.json for version: ${(error as Error)?.message ?? 'Unknown error'}`); + } + return version; +} + function setContext(context: Context, module?: string) { logger.addPersistentLogAttributes({ 'aws-request-id': context.awsRequestId, 'function-name': context.functionName, + version: getReleaseVersion(), module: module, }); @@ -20,6 +37,7 @@ function setContext(context: Context, module?: string) { childLogger.addPersistentLogAttributes({ 'aws-request-id': context.awsRequestId, 'function-name': context.functionName, + version: getReleaseVersion(), }); }); } diff --git a/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts b/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts index bcdc44f677..704bdbe89e 100644 --- a/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts +++ b/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts @@ -1,7 +1,8 @@ import { Context } from 'aws-lambda'; +import * as fs from 'fs'; +import * as path from 'path'; -import { logger, setContext } from '../'; -import { describe, test, expect, beforeEach, vi } from 'vitest'; +import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest'; beforeEach(() => { vi.clearAllMocks(); @@ -29,6 +30,31 @@ const context: Context = { }, }; +const versionFilePath = path.resolve(__dirname, 'version.json'); + +let logger: typeof import('../').logger; +let setContext: typeof import('../').setContext; + +beforeEach(async () => { + // Clear the module cache and reload the logger module + vi.resetModules(); + const loggerModule = await import('../'); + logger = loggerModule.logger; + setContext = loggerModule.setContext; + + // Ensure a clean state before each test + if (fs.existsSync(versionFilePath)) { + fs.unlinkSync(versionFilePath); + } +}); + +afterEach(() => { + // Clean up after each test + if (fs.existsSync(versionFilePath)) { + fs.unlinkSync(versionFilePath); + } +}); + describe('A root logger.', () => { test('Should log set context.', async () => { setContext(context, 'unit-test'); @@ -42,3 +68,52 @@ describe('A root logger.', () => { ); }); }); + +describe('Logger version handling', () => { + test('Should not fail if package.json does not exist', () => { + const packageFilePath = path.resolve(__dirname, 'package.json'); + + // Temporarily rename package.json to simulate its absence + const tempFilePath = `${packageFilePath}.bak`; + if (fs.existsSync(packageFilePath)) { + fs.renameSync(packageFilePath, tempFilePath); + } + + setContext(context, 'unit-test'); + + expect(logger.getPersistentLogAttributes()).toEqual( + expect.objectContaining({ + version: 'unknown', + }), + ); + + // Restore package.json + if (fs.existsSync(tempFilePath)) { + fs.renameSync(tempFilePath, packageFilePath); + } + }); + + test('Should log version from package.json', () => { + const packageFilePath = path.resolve(__dirname, 'package.json'); + + // Create a mock package.json file + const originalPackageData = fs.existsSync(packageFilePath) ? fs.readFileSync(packageFilePath, 'utf-8') : null; + const mockPackageData = JSON.stringify({ version: '1.0.0' }); + fs.writeFileSync(packageFilePath, mockPackageData); + + setContext(context, 'unit-test'); + + expect(logger.getPersistentLogAttributes()).toEqual( + expect.objectContaining({ + version: '1.0.0', + }), + ); + + // Restore the original package.json file + if (originalPackageData) { + fs.writeFileSync(packageFilePath, originalPackageData); + } else { + fs.unlinkSync(packageFilePath); + } + }); +}); From 623e9add84724ce3eea782918f30bb0a3d78da1e Mon Sep 17 00:00:00 2001 From: Niek Palm Date: Fri, 4 Jul 2025 07:49:17 +0200 Subject: [PATCH 2/3] Update logger.test.ts --- lambdas/libs/aws-powertools-util/src/logger/logger.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts b/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts index 704bdbe89e..9790ed37bd 100644 --- a/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts +++ b/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts @@ -30,7 +30,7 @@ const context: Context = { }, }; -const versionFilePath = path.resolve(__dirname, 'version.json'); +const versionFilePath = path.resolve(__dirname, 'package.json'); let logger: typeof import('../').logger; let setContext: typeof import('../').setContext; From d7b089874d16b5c72d08fae3f6af3aa1b24b6558 Mon Sep 17 00:00:00 2001 From: Niek Palm Date: Fri, 4 Jul 2025 07:56:36 +0200 Subject: [PATCH 3/3] clean-up vibe coding collaterals --- .../src/logger/logger.test.ts | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts b/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts index 9790ed37bd..b68668b2a1 100644 --- a/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts +++ b/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts @@ -71,12 +71,10 @@ describe('A root logger.', () => { describe('Logger version handling', () => { test('Should not fail if package.json does not exist', () => { - const packageFilePath = path.resolve(__dirname, 'package.json'); - // Temporarily rename package.json to simulate its absence - const tempFilePath = `${packageFilePath}.bak`; - if (fs.existsSync(packageFilePath)) { - fs.renameSync(packageFilePath, tempFilePath); + const tempFilePath = `${versionFilePath}.bak`; + if (fs.existsSync(versionFilePath)) { + fs.renameSync(versionFilePath, tempFilePath); } setContext(context, 'unit-test'); @@ -89,17 +87,15 @@ describe('Logger version handling', () => { // Restore package.json if (fs.existsSync(tempFilePath)) { - fs.renameSync(tempFilePath, packageFilePath); + fs.renameSync(tempFilePath, versionFilePath); } }); test('Should log version from package.json', () => { - const packageFilePath = path.resolve(__dirname, 'package.json'); - // Create a mock package.json file - const originalPackageData = fs.existsSync(packageFilePath) ? fs.readFileSync(packageFilePath, 'utf-8') : null; + const originalPackageData = fs.existsSync(versionFilePath) ? fs.readFileSync(packageFilePath, 'utf-8') : null; const mockPackageData = JSON.stringify({ version: '1.0.0' }); - fs.writeFileSync(packageFilePath, mockPackageData); + fs.writeFileSync(versionFilePath, mockPackageData); setContext(context, 'unit-test'); @@ -111,9 +107,9 @@ describe('Logger version handling', () => { // Restore the original package.json file if (originalPackageData) { - fs.writeFileSync(packageFilePath, originalPackageData); + fs.writeFileSync(versionFilePath, originalPackageData); } else { - fs.unlinkSync(packageFilePath); + fs.unlinkSync(versionFilePath); } }); });