├── roleAfterApplication.json ├── examples ├── python-requirements │ ├── sample_app │ │ ├── __init__.py │ │ └── handlers.py │ ├── requirements.txt │ ├── serverless.yml │ ├── package.json │ └── .gitignore ├── python │ ├── handler.py │ ├── package.json │ ├── .gitignore │ └── serverless.yml ├── ruby │ ├── Gemfile │ ├── package.json │ ├── serverless.yml │ ├── .gitignore │ └── app.rb ├── nodejs │ ├── handler.js │ ├── package.json │ ├── .gitignore │ └── serverless.yml ├── java │ ├── .gitignore │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── serverless │ │ │ └── Handler.java │ ├── package.json │ ├── serverless.yml │ ├── java-example.iml │ └── pom.xml ├── dotnet │ ├── handler.cs │ ├── serverless.yml │ ├── build.sh │ ├── aws-lambda-tools-defaults.json │ ├── package.json │ ├── NewrelicExample.csproj │ └── readme.md └── README.md ├── .husky └── pre-commit ├── jest.config.js ├── tslint.json ├── tsconfig.json ├── .github ├── workflows │ ├── create-release.yml │ ├── prepare-release.yml │ ├── repolinter.yml │ ├── ci-workflow.yml │ └── validate-pr.yml ├── dependabot.yml └── PULL_REQUEST_TEMPLATE.md ├── THIRD_PARTY_NOTICES.md ├── tests ├── fixtures │ ├── manual-wrapping.input.service.json │ ├── ingest-key-only.input.service.json │ ├── proxy.input.service.json │ ├── lambda-extension-enabled.input.service.json │ ├── lambda-extension-disabled.input.service.json │ ├── api-and-ingest-key.input.service.json │ ├── provider-layer.input.service.json │ ├── trusted-account-key-excluded.input.service.json │ ├── distributed-tracing-enabled.input.service.json │ ├── license-key-secret-disabled.input.service.json │ ├── include-exclude.input.service.json │ ├── include-exclude.output.service.json │ ├── stage-excluded.input.service.json │ ├── stage-excluded.output.service.json │ ├── include.input.service.json │ ├── stage-included.input.service.json │ ├── debug.input.service.json │ ├── log-disabled.input.service.json │ ├── log-level.input.service.json │ ├── eu.input.service.json │ ├── function-has-layers.input.service.json │ ├── includes-all-provider-layer.input.service.json │ ├── trusted-account-key-included.input.service.json │ ├── debug-log-level.input.service.json │ ├── log-ingestion-via-extension.input.service.json │ ├── provider-environment.input.service.json │ ├── provider-environment-log-level.input.service.json │ ├── license-key-null.input.service.json │ ├── arm64.input.service.json │ ├── arm64-unsupported.input.service.json │ ├── license-key-null.output.service.json │ ├── manual-wrapping.output.service.json │ ├── include.output.service.json │ ├── arm64-unsupported.output.service.json │ ├── provider-layer.output.service.json │ ├── node-versions.input.service.json │ ├── includes-all-provider-layer.output.service.json │ ├── trusted-account-key-excluded.output.service.json │ ├── ingest-key-only.output.service.json │ ├── stage-included.output.service.json │ ├── log-disabled.output.service.json │ ├── api-and-ingest-key.output.service.json │ ├── trusted-account-key-included.output.service.json │ ├── function-has-layers.output.service.json │ ├── lambda-extension-enabled.output.service.json │ ├── lambda-extension-disabled.output.service.json │ ├── proxy.output.service.json │ ├── debug.output.service.json │ ├── distributed-tracing-enabled.output.service.json │ ├── log-level.output.service.json │ ├── arm64.output.service.json │ ├── license-key-secret-disabled.output.service.json │ ├── debug-log-level.output.service.json │ ├── provider-environment.output.service.json │ ├── provider-environment-log-level.output.service.json │ ├── eu.output.service.json │ ├── log-ingestion-via-extension.output.service.json │ └── node-versions.output.service.json ├── paginatedFunctionsList.json ├── paginatedPoliciesList.json └── integration.test.ts ├── .gitignore ├── src ├── utils.ts └── api.ts ├── templates ├── nr-license-key-secret.yaml └── nr-lambda-integration-role.yaml ├── package.json ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md ├── LICENSE └── README.md /roleAfterApplication.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/python-requirements/sample_app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/python-requirements/requirements.txt: -------------------------------------------------------------------------------- 1 | newrelic 2 | -------------------------------------------------------------------------------- /examples/python/handler.py: -------------------------------------------------------------------------------- 1 | def handler(event, context): 2 | return 200 3 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | -------------------------------------------------------------------------------- /examples/ruby/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "httparty" 4 | 5 | ruby '~> 3.3' 6 | -------------------------------------------------------------------------------- /examples/python-requirements/sample_app/handlers.py: -------------------------------------------------------------------------------- 1 | def handler(event, context): 2 | return "hi there" 3 | -------------------------------------------------------------------------------- /examples/nodejs/handler.js: -------------------------------------------------------------------------------- 1 | module.exports.handler = (event, context, callback) => { 2 | callback(null, 'hi there'); 3 | }; 4 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | testEnvironment: "node", 4 | collectCoverage: true, 5 | coverageReporters: ["lcov", "html"], 6 | testTimeout: 30000 7 | }; 8 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:latest", "tslint-config-prettier"], 3 | "rulesDirectory": ["tslint-plugin-prettier"], 4 | "rules": {"prettier": true, "no-submodule-imports": false} 5 | } 6 | -------------------------------------------------------------------------------- /examples/java/.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | target 3 | node_modules 4 | /bin/ 5 | /.settings/ 6 | .project 7 | .classpath 8 | .idea 9 | 10 | # Package Files 11 | *.jar 12 | *.war 13 | *.ear 14 | 15 | # Serverless directories 16 | .serverless 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "module": "commonjs", 5 | "outDir": "dist", 6 | "target": "es6" 7 | }, 8 | "include": [ 9 | "src" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: Create Release 2 | 3 | on: [workflow_dispatch] 4 | 5 | # Since we are reusing a workflow, we must match the permissions that 6 | # upstream workflow requires. 7 | permissions: 8 | contents: write 9 | id-token: write 10 | 11 | jobs: 12 | tag-and-publish: 13 | uses: newrelic/node-newrelic/.github/workflows/release-creation.yml@main 14 | with: 15 | changelog_file: CHANGELOG.md 16 | build: true 17 | -------------------------------------------------------------------------------- /examples/dotnet/handler.cs: -------------------------------------------------------------------------------- 1 | using Amazon.Lambda.Core; 2 | using System.Threading.Tasks; 3 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] 4 | 5 | namespace NewrelicExample; 6 | 7 | public class Function 8 | { 9 | public async Task FunctionHandler(ILambdaContext context) 10 | { 11 | await Task.Delay(1000); // Simulate some async work 12 | return "Hello, World!"; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | # Disable version updates for npm dependencies, security updates don't use this configuration 5 | # See: https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates 6 | open-pull-requests-limit: 0 7 | directory: "/" 8 | schedule: 9 | interval: "daily" 10 | commit-message: 11 | prefix: "security" 12 | prefix-development: "chore" 13 | include: "scope" -------------------------------------------------------------------------------- /examples/dotnet/serverless.yml: -------------------------------------------------------------------------------- 1 | service: newrelic-serverless-dotnet-example 2 | 3 | 4 | 5 | provider: 6 | name: aws 7 | stage: prod 8 | region: us-east-1 9 | 10 | package: 11 | artifact: 'newrelic-serverless-dotnet-example.zip' 12 | 13 | plugins: 14 | - serverless-newrelic-lambda-layers 15 | 16 | custom: 17 | newRelic: 18 | accountId: ${env:NEW_RELIC_ACCOUNT_ID} 19 | apiKey: ${env:NEW_RELIC_PERSONAL_API_KEY} 20 | logLevel: debug 21 | 22 | functions: 23 | layer-dotnet8: 24 | handler: NewrelicExample::NewrelicExample.Function::FunctionHandler 25 | runtime: dotnet8 26 | -------------------------------------------------------------------------------- /.github/workflows/prepare-release.yml: -------------------------------------------------------------------------------- 1 | name: Prepare Release PR 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_type: 7 | description: Type of release. patch or minor (major if breaking) 8 | required: true 9 | type: choice 10 | default: patch 11 | options: 12 | - patch 13 | - minor 14 | - major 15 | 16 | jobs: 17 | release-notes: 18 | uses: newrelic/node-newrelic/.github/workflows/prep-release.yml@main 19 | with: 20 | release_type: ${{ github.event.inputs.release_type }} 21 | changelog_file: CHANGELOG.md 22 | -------------------------------------------------------------------------------- /examples/java/src/main/java/com/serverless/Handler.java: -------------------------------------------------------------------------------- 1 | package com.serverless; 2 | 3 | import java.util.Map; 4 | 5 | import org.apache.logging.log4j.LogManager; 6 | import org.apache.logging.log4j.Logger; 7 | 8 | import com.amazonaws.services.lambda.runtime.Context; 9 | import com.amazonaws.services.lambda.runtime.RequestHandler; 10 | 11 | public class Handler implements RequestHandler, String> { 12 | 13 | private static final Logger LOG = LogManager.getLogger(Handler.class); 14 | 15 | @Override 16 | public String handleRequest(Map input, Context context) { 17 | LOG.info("received: {}", input); 18 | return "ok"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/dotnet/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install zip on Debian-based systems 4 | if [ -f /etc/debian_version ]; then 5 | apt -qq update 6 | apt -qq -y install zip 7 | 8 | # Install required tools if not installed 9 | dotnet tool list -g | grep -q Amazon.Lambda.Tools 10 | if [ $? -ne 0 ]; then 11 | dotnet tool install -g Amazon.Lambda.Tools 12 | fi 13 | 14 | # Ensure the global tools path is accessible 15 | export PATH="$PATH:/root/.dotnet/tools" 16 | fi 17 | 18 | dotnet restore 19 | # update the dotnet framework as per your project and ensure the global tools path is accessible 20 | dotnet lambda package --configuration Debug --framework net8.0 --output-package newrelic-serverless-dotnet-example.zip 21 | -------------------------------------------------------------------------------- /examples/dotnet/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "framework": "net8.0", 12 | "function-runtime": "dotnet8", 13 | "function-architecture": "x86_64", 14 | "function-memory-size": 512, 15 | "function-timeout": 30 16 | } 17 | -------------------------------------------------------------------------------- /examples/python-requirements/serverless.yml: -------------------------------------------------------------------------------- 1 | service: newrelic-lambda-layers-python-reqs 2 | 3 | provider: 4 | name: aws 5 | stage: test 6 | region: us-east-1 7 | runtime: python3.13 8 | 9 | plugins: 10 | - serverless-python-requirements 11 | - serverless-newrelic-lambda-layers 12 | 13 | custom: 14 | newRelic: 15 | accountId: ${env:NEW_RELIC_ACCOUNT_ID} 16 | apiKey: ${env:NEW_RELIC_PERSONAL_API_KEY} 17 | debug: true 18 | pythonRequirements: 19 | dockerizePip: true 20 | layer: true 21 | 22 | functions: 23 | layer-python313: 24 | events: 25 | - schedule: rate(5 minutes) 26 | handler: sample_app.handlers.handler 27 | package: 28 | exclude: 29 | - ./** 30 | include: 31 | - ./sample_app/** 32 | -------------------------------------------------------------------------------- /examples/java/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-newrelic-lambda-layers-nodejs-example", 3 | "version": "0.0.0-test", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run clean && npm run buildPlugin && npm run buildPackage", 8 | "buildPackage": "LOCAL_PLUGIN=true SLS_DEBUG=* sls package", 9 | "buildPlugin": "cd ../../ && npm run build && mkdir -p examples/nodejs/.serverless_plugins && cp -rf dist examples/nodejs/.serverless_plugins/serverless-newrelic-lambda-layers", 10 | "clean": "rm -rf .serverless_plugins", 11 | "deploy": "yarn build && sls deploy" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "serverless": "^3.3.0", 17 | "serverless-newrelic-lambda-layers": "^3.0.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/dotnet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-newrelic-lambda-layers-dotnet-example", 3 | "version": "0.0.0-test", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run clean && npm run buildPlugin && npm run buildPackage", 8 | "buildPackage": "LOCAL_PLUGIN=true SLS_DEBUG=* sls package", 9 | "buildPlugin": "cd ../../ && npm run build && mkdir -p examples/dotnet/.serverless_plugins && cp -rf dist examples/dotnet/.serverless_plugins/serverless-newrelic-lambda-layers", 10 | "clean": "rm -rf .serverless_plugins", 11 | "deploy": "yarn build && sls deploy" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "serverless": "^4.12.0", 17 | "serverless-newrelic-lambda-layers": "^5.7.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES.md: -------------------------------------------------------------------------------- 1 | # Third Party Notices 2 | 3 | The serverless-newrelic-lambda-layers project uses source code from third party libraries which carry 4 | their own copyright notices and license terms. These notices are provided 5 | below. 6 | 7 | In the event that a required notice is missing or incorrect, please notify us 8 | by e-mailing [open-source@newrelic.com](mailto:open-source@newrelic.com). 9 | 10 | For any licenses that require the disclosure of source 11 | code, the source code can be found at [https://github.com/newrelic/serverless-newrelic-lambda-layers](https://github.com/newrelic/serverless-newrelic-lambda-layers). 12 | 13 | ## Content 14 | 15 | **[dependencies](#dependencies)** 16 | 17 | N/A 18 | 19 | **[devDependencies](#devDependencies)** 20 | 21 | * eslint 22 | * eslint-plugin-import 23 | -------------------------------------------------------------------------------- /examples/ruby/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-newrelic-lambda-layers-ruby-example", 3 | "version": "0.0.0-test", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run clean && npm run buildPlugin && npm run buildPackage", 8 | "buildPackage": "LOCAL_PLUGIN=true SLS_DEBUG=* sls package", 9 | "buildPlugin": "cd ../../ && npm run build && mkdir -p examples/ruby/.serverless_plugins && cp -rf dist examples/ruby/.serverless_plugins/serverless-newrelic-lambda-layers", 10 | "clean": "rm -rf .serverless_plugins", 11 | "deploy": "yarn build && sls deploy" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "serverless": "^4.12.0" 17 | }, 18 | "dependencies": { 19 | "serverless-newrelic-lambda-layers": "^5.12.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-newrelic-lambda-layers-nodejs-example", 3 | "version": "0.0.0-test", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run clean && npm run buildPlugin && npm run buildPackage", 8 | "buildPackage": "LOCAL_PLUGIN=true SLS_DEBUG=* sls package", 9 | "buildPlugin": "cd ../../ && npm run build && mkdir -p examples/nodejs/.serverless_plugins && cp -rf dist examples/nodejs/.serverless_plugins/serverless-newrelic-lambda-layers", 10 | "clean": "rm -rf .serverless_plugins", 11 | "deploy": "yarn build && sls deploy" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "serverless": "^4.12.0" 17 | }, 18 | "dependencies": { 19 | "serverless-newrelic-lambda-layers": "^5.12.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/python/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-newrelic-lambda-layers-python-example", 3 | "version": "0.0.0-test", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run clean && npm run buildPlugin && npm run buildPackage", 8 | "buildPackage": "LOCAL_PLUGIN=true SLS_DEBUG=* sls package", 9 | "buildPlugin": "cd ../../ && npm run build && mkdir -p examples/python/.serverless_plugins && cp -rf dist examples/python/.serverless_plugins/serverless-newrelic-lambda-layers", 10 | "clean": "rm -rf .serverless_plugins", 11 | "deploy": "yarn build && sls deploy" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "serverless": "^4.12.0" 17 | }, 18 | "dependencies": { 19 | "serverless-newrelic-lambda-layers": "^5.12.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/python-requirements/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-newrelic-lambda-layers-python-requirements", 3 | "version": "0.0.0-test", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run clean && npm run buildPlugin && npm run buildPackage", 8 | "buildPackage": "LOCAL_PLUGIN=true SLS_DEBUG=* sls package", 9 | "buildPlugin": "cd ../../ && npm run build && mkdir -p examples/python-requirements/.serverless_plugins && cp -rf dist examples/python-requirements/.serverless_plugins/serverless-newrelic-lambda-layers", 10 | "clean": "rm -rf .serverless_plugins", 11 | "deploy": "yarn build && sls deploy" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "serverless": "^4.12.0", 17 | "serverless-python-requirements": "^5.3.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/dotnet/NewrelicExample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library 4 | net8.0 5 | enable 6 | enable 7 | true 8 | Lambda 9 | true 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/ruby/serverless.yml: -------------------------------------------------------------------------------- 1 | service: newrelic-ruby-test 2 | 3 | provider: 4 | name: aws 5 | stage: prod 6 | region: us-east-1 7 | 8 | plugins: 9 | - serverless-newrelic-lambda-layers 10 | 11 | custom: 12 | newRelic: 13 | accountId: ${env:NEW_RELIC_ACCOUNT_ID} 14 | apiKey: ${env:NEW_RELIC_PERSONAL_API_KEY} 15 | logLevel: debug 16 | 17 | functions: 18 | layer-ruby32: 19 | handler: app.lambda_handler 20 | package: 21 | exclude: 22 | - ./** 23 | include: 24 | - app.rb 25 | runtime: ruby3.2 26 | 27 | layer-ruby33: 28 | handler: app.lambda_handler 29 | package: 30 | exclude: 31 | - ./** 32 | include: 33 | - app.rb 34 | runtime: ruby3.3 35 | 36 | layer-ruby34: 37 | handler: app.lambda_handler 38 | package: 39 | exclude: 40 | - ./** 41 | include: 42 | - app.rb 43 | runtime: ruby3.4 44 | -------------------------------------------------------------------------------- /examples/java/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: java-example 15 | 16 | provider: 17 | name: aws 18 | runtime: java11 19 | region: us-west-1 20 | stage: dev 21 | 22 | package: 23 | artifact: 'target/${self:service}-${self:provider.stage}.jar' 24 | 25 | plugins: 26 | - serverless-newrelic-lambda-layers 27 | 28 | custom: 29 | newRelic: 30 | accountId: ${env:NEW_RELIC_ACCOUNT_ID} 31 | apiKey: ${env:NEW_RELIC_PERSONAL_API_KEY} 32 | logLevel: debug 33 | functions: 34 | listProducts: 35 | handler: com.serverless.Handler 36 | 37 | 38 | -------------------------------------------------------------------------------- /tests/fixtures/manual-wrapping.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "custom": { 20 | "newRelic": { 21 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 22 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 23 | "logLevel": "debug", 24 | "manualWrapping": true 25 | } 26 | }, 27 | "functions": { 28 | "layer-nodejs18x": { 29 | "events": [{ "schedule": "rate(5 minutes)" }], 30 | "handler": "handler.handler", 31 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 32 | "runtime": "nodejs18.x" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 15 | ## Description 16 | 17 | Please provide a brief description of the changes introduced in this pull request. 18 | What problem does it solve? What is the context of this change? 19 | 20 | ## How to Test 21 | 22 | Please describe how you have tested these changes. Have you run the code against an example application? 23 | What steps did you take to ensure that the changes are working correctly? 24 | 25 | ## Related Issues 26 | 27 | Please include any related issues or pull requests in this section, using the format `Closes #` or `Fixes #` if applicable. -------------------------------------------------------------------------------- /tests/fixtures/ingest-key-only.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "custom": { 20 | "newRelic": { 21 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 22 | "ingestKey": "test-ingest-key", 23 | "logLevel": "debug" 24 | } 25 | }, 26 | "functions": { 27 | "layer-nodejs16x": { 28 | "events": [{ "schedule": "rate(5 minutes)" }], 29 | "handler": "handler.handler", 30 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 31 | "runtime": "nodejs16.x" 32 | }, 33 | "layer-nodejs18x": { 34 | "events": [{ "schedule": "rate(5 minutes)" }], 35 | "handler": "handler.handler", 36 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 37 | "runtime": "nodejs18.x" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /examples/ruby/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | dist/ 64 | .serverless 65 | .serverless_plugins 66 | -------------------------------------------------------------------------------- /examples/nodejs/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | dist/ 64 | .serverless 65 | .serverless_plugins 66 | -------------------------------------------------------------------------------- /examples/python/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | dist/ 64 | .serverless 65 | .serverless_plugins 66 | -------------------------------------------------------------------------------- /examples/python-requirements/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | dist/ 64 | .serverless 65 | .serverless_plugins 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | dist/ 64 | .env 65 | .idea/ 66 | 67 | .DS_Store 68 | example.service.input.json 69 | -------------------------------------------------------------------------------- /tests/fixtures/proxy.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "custom": { 20 | "newRelic": { 21 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 22 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 23 | "proxy": "http://myproxy.com:8080" 24 | } 25 | }, 26 | "functions": { 27 | "layer-nodejs16x": { 28 | "events": [{ "schedule": "rate(5 minutes)" }], 29 | "handler": "handler.handler", 30 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 31 | "runtime": "nodejs16.x" 32 | }, 33 | "layer-nodejs18x": { 34 | "events": [{ "schedule": "rate(5 minutes)" }], 35 | "handler": "handler.handler", 36 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 37 | "runtime": "nodejs18.x" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/fixtures/lambda-extension-enabled.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "custom": { 20 | "newRelic": { 21 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 22 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 23 | "logLevel": "debug" 24 | } 25 | }, 26 | "functions": { 27 | "layer-nodejs16x": { 28 | "events": [{ "schedule": "rate(5 minutes)" }], 29 | "handler": "handler.handler", 30 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 31 | "runtime": "nodejs16.x" 32 | }, 33 | "layer-nodejs18x": { 34 | "events": [{ "schedule": "rate(5 minutes)" }], 35 | "handler": "handler.handler", 36 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 37 | "runtime": "nodejs18.x" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/fixtures/lambda-extension-disabled.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "custom": { 20 | "newRelic": { 21 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 22 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 23 | "enableExtension": false 24 | } 25 | }, 26 | "functions": { 27 | "layer-nodejs16x": { 28 | "events": [{ "schedule": "rate(5 minutes)" }], 29 | "handler": "handler.handler", 30 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 31 | "runtime": "nodejs16.x" 32 | }, 33 | "layer-nodejs18x": { 34 | "events": [{ "schedule": "rate(5 minutes)" }], 35 | "handler": "handler.handler", 36 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 37 | "runtime": "nodejs18.x" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/ruby/app.rb: -------------------------------------------------------------------------------- 1 | # require 'httparty' 2 | require 'json' 3 | 4 | def lambda_handler(event:, context:) 5 | # Sample pure Lambda function 6 | 7 | # Parameters 8 | # ---------- 9 | # event: Hash, required 10 | # API Gateway Lambda Proxy Input Format 11 | # Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format 12 | 13 | # context: object, required 14 | # Lambda Context runtime methods and attributes 15 | # Context doc: https://docs.aws.amazon.com/lambda/latest/dg/ruby-context.html 16 | 17 | # Returns 18 | # ------ 19 | # API Gateway Lambda Proxy Output Format: dict 20 | # 'statusCode' and 'body' are required 21 | # # api-gateway-simple-proxy-for-lambda-output-format 22 | # Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html 23 | 24 | # begin 25 | # response = HTTParty.get('http://checkip.amazonaws.com/') 26 | # rescue HTTParty::Error => error 27 | # puts error.inspect 28 | # raise error 29 | # end 30 | 31 | { 32 | statusCode: 200, 33 | body: { 34 | message: "Hello World!", 35 | # location: response.body 36 | }.to_json 37 | } 38 | end 39 | -------------------------------------------------------------------------------- /tests/fixtures/api-and-ingest-key.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "custom": { 20 | "newRelic": { 21 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 22 | "apiKey": "test-api-key", 23 | "ingestKey": "test-ingest-key", 24 | "logLevel": "debug" 25 | } 26 | }, 27 | "functions": { 28 | "layer-nodejs16x": { 29 | "events": [{ "schedule": "rate(5 minutes)" }], 30 | "handler": "handler.handler", 31 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 32 | "runtime": "nodejs16.x" 33 | }, 34 | "layer-nodejs18x": { 35 | "events": [{ "schedule": "rate(5 minutes)" }], 36 | "handler": "handler.handler", 37 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 38 | "runtime": "nodejs18.x" 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /tests/fixtures/provider-layer.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}" 24 | } 25 | }, 26 | "disabledDeprecations": [], 27 | "functions": { 28 | "layer-nodejs18x1": { 29 | "events": [{ "schedule": "rate(5 minutes)" }], 30 | "handler": "handler.handler", 31 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 32 | "runtime": "nodejs18.x" 33 | }, 34 | "layer-nodejs18x2": { 35 | "events": [{ "schedule": "rate(5 minutes)" }], 36 | "handler": "handler.handler", 37 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 38 | "runtime": "nodejs18.x" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/repolinter.yml: -------------------------------------------------------------------------------- 1 | # NOTE: This file should always be named `repolinter.yml` to allow 2 | # workflow_dispatch to work properly 3 | name: Repolinter Action 4 | 5 | # NOTE: This workflow will ONLY check the default branch! 6 | # Currently there is no elegant way to specify the default 7 | # branch in the event filtering, so branches are instead 8 | # filtered in the "Test Default Branch" step. 9 | on: [push, workflow_dispatch] 10 | 11 | jobs: 12 | repolint: 13 | name: Run Repolinter 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Test Default Branch 17 | id: default-branch 18 | uses: actions/github-script@v6 19 | with: 20 | script: | 21 | const data = await github.rest.repos.get(context.repo) 22 | return data.data && data.data.default_branch === context.ref.split('/').slice(-1)[0] 23 | - name: Checkout Self 24 | if: ${{ steps.default-branch.outputs.result == 'true' }} 25 | uses: actions/checkout@v4 26 | - name: Run Repolinter 27 | if: ${{ steps.default-branch.outputs.result == 'true' }} 28 | uses: newrelic/repolinter-action@v1 29 | with: 30 | config_url: https://raw.githubusercontent.com/newrelic/.github/main/repolinter-rulesets/community-plus.yml 31 | output_type: issue 32 | -------------------------------------------------------------------------------- /tests/fixtures/trusted-account-key-excluded.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}" 24 | } 25 | }, 26 | "disabledDeprecations": [], 27 | "functions": { 28 | "layer-nodejs16x": { 29 | "events": [{ "schedule": "rate(5 minutes)" }], 30 | "handler": "handler.handler", 31 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 32 | "runtime": "nodejs16.x" 33 | }, 34 | "layer-nodejs18x": { 35 | "events": [{ "schedule": "rate(5 minutes)" }], 36 | "handler": "handler.handler", 37 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 38 | "runtime": "nodejs18.x" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/fixtures/distributed-tracing-enabled.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "custom": { 20 | "newRelic": { 21 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 22 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 23 | "enableDistributedTracing": true, 24 | "logLevel": "debug" 25 | } 26 | }, 27 | "functions": { 28 | "layer-nodejs16x": { 29 | "events": [{ "schedule": "rate(5 minutes)" }], 30 | "handler": "handler.handler", 31 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 32 | "runtime": "nodejs16.x" 33 | }, 34 | "layer-nodejs18x": { 35 | "events": [{ "schedule": "rate(5 minutes)" }], 36 | "handler": "handler.handler", 37 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 38 | "runtime": "nodejs18.x" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/fixtures/license-key-secret-disabled.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "custom": { 20 | "newRelic": { 21 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 22 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 23 | "logLevel": "debug", 24 | "disableLicenseKeySecret": false 25 | } 26 | }, 27 | "functions": { 28 | "layer-nodejs16x": { 29 | "events": [{ "schedule": "rate(5 minutes)" }], 30 | "handler": "handler.handler", 31 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 32 | "runtime": "nodejs16.x" 33 | }, 34 | "layer-nodejs18x": { 35 | "events": [{ "schedule": "rate(5 minutes)" }], 36 | "handler": "handler.handler", 37 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 38 | "runtime": "nodejs18.x" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/fixtures/include-exclude.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "include": ["layer-nodejs16x"], 24 | "exclude": ["layer-nodejs18x"] 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs16.x" 34 | }, 35 | "layer-nodejs18x": { 36 | "events": [{ "schedule": "rate(5 minutes)" }], 37 | "handler": "handler.handler", 38 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 39 | "runtime": "nodejs18.x" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/fixtures/include-exclude.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "include": ["layer-nodejs16x"], 24 | "exclude": ["layer-nodejs18x"] 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs16.x" 34 | }, 35 | "layer-nodejs18x": { 36 | "events": [{ "schedule": "rate(5 minutes)" }], 37 | "handler": "handler.handler", 38 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 39 | "runtime": "nodejs18.x" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/fixtures/stage-excluded.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "dev", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "stages": ["prod"] 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs16.x" 34 | }, 35 | "layer-nodejs18x": { 36 | "events": [{ "schedule": "rate(5 minutes)" }], 37 | "handler": "handler.handler", 38 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 39 | "runtime": "nodejs18.x" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/fixtures/stage-excluded.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "dev", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "stages": ["prod"] 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs16.x" 34 | }, 35 | "layer-nodejs18x": { 36 | "events": [{ "schedule": "rate(5 minutes)" }], 37 | "handler": "handler.handler", 38 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 39 | "runtime": "nodejs18.x" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/fixtures/include.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "include": ["layer-nodejs18x"] 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs16.x" 34 | }, 35 | "layer-nodejs18x": { 36 | "events": [{ "schedule": "rate(5 minutes)" }], 37 | "handler": "handler.handler", 38 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 39 | "runtime": "nodejs18.x" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/fixtures/stage-included.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "dev", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "stages": ["dev", "prod"] 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs16.x" 34 | }, 35 | "layer-nodejs18x": { 36 | "events": [{ "schedule": "rate(5 minutes)" }], 37 | "handler": "handler.handler", 38 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 39 | "runtime": "nodejs18.x" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { readFile } from "fs/promises"; 2 | import * as _ from "lodash"; 3 | import * as path from "path"; 4 | 5 | export const waitForStatus = async ( 6 | requestParams: any, 7 | serverlessProps: any, 8 | retryCount: number = 0 9 | ) => { 10 | const { awsProvider, log } = serverlessProps; 11 | const { awsMethod, callbackMethod, methodParams, statusPath } = requestParams; 12 | 13 | try { 14 | const resourceStatus = await awsProvider.request( 15 | "CloudFormation", 16 | awsMethod, 17 | methodParams 18 | ); 19 | const status = _.get(resourceStatus, statusPath); 20 | 21 | if (status.includes("FAILED") || retryCount > 120) { 22 | throw new Error(); 23 | } else if (status === "CREATE_COMPLETE") { 24 | log("Resource successfully created."); 25 | callbackMethod(); 26 | return; 27 | } 28 | 29 | setTimeout( 30 | () => waitForStatus(requestParams, serverlessProps, retryCount + 1), 31 | 30000 32 | ); 33 | } catch (stackErr) { 34 | log(`Something went wrong while creating aws resource: ${stackErr}`); 35 | } 36 | }; 37 | 38 | export const fetchPolicy = async (templatePolicy: string) => { 39 | const policy = await readFile( 40 | path.resolve(__dirname, "..", "templates", templatePolicy), 41 | { encoding: "utf8" } 42 | ); 43 | return policy; 44 | }; 45 | -------------------------------------------------------------------------------- /tests/fixtures/debug.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "debug": true, 25 | "logEnabled": true 26 | } 27 | }, 28 | "disabledDeprecations": [], 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [{ "schedule": "rate(5 minutes)" }], 32 | "handler": "handler.handler", 33 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 34 | "runtime": "nodejs16.x" 35 | }, 36 | "layer-nodejs18x": { 37 | "events": [{ "schedule": "rate(5 minutes)" }], 38 | "handler": "handler.handler", 39 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 40 | "runtime": "nodejs18.x" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/fixtures/log-disabled.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "logLevel": "error", 25 | "debug": true 26 | } 27 | }, 28 | "disabledDeprecations": [], 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [{ "schedule": "rate(5 minutes)" }], 32 | "handler": "handler.handler", 33 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 34 | "runtime": "nodejs16.x" 35 | }, 36 | "layer-nodejs18x": { 37 | "events": [{ "schedule": "rate(5 minutes)" }], 38 | "handler": "handler.handler", 39 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 40 | "runtime": "nodejs18.x" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/fixtures/log-level.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "logLevel": "error", 25 | "logEnabled": true 26 | } 27 | }, 28 | "disabledDeprecations": [], 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [{ "schedule": "rate(5 minutes)" }], 32 | "handler": "handler.handler", 33 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 34 | "runtime": "nodejs16.x" 35 | }, 36 | "layer-nodejs18x": { 37 | "events": [{ "schedule": "rate(5 minutes)" }], 38 | "handler": "handler.handler", 39 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 40 | "runtime": "nodejs18.x" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/fixtures/eu.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "debug": true, 25 | "nrRegion": "eu", 26 | "logEnabled": true 27 | } 28 | }, 29 | "disabledDeprecations": [], 30 | "functions": { 31 | "layer-nodejs16x": { 32 | "events": [{ "schedule": "rate(5 minutes)" }], 33 | "handler": "handler.handler", 34 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 35 | "runtime": "nodejs16.x" 36 | }, 37 | "layer-nodejs18x": { 38 | "events": [{ "schedule": "rate(5 minutes)" }], 39 | "handler": "handler.handler", 40 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 41 | "runtime": "nodejs18.x" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/fixtures/function-has-layers.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": [ 19 | "serverless-newrelic-lambda-layers" 20 | ], 21 | "custom": { 22 | "newRelic": { 23 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 24 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 25 | "logLevel": "debug" 26 | } 27 | }, 28 | "functions": { 29 | "layer-nodejs18x1": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs18.x", 34 | "layers": ["arn:aws:lambda:us-east-1:123456789012:layer:SomeOtherLayer:1"] 35 | }, 36 | "layer-nodejs18x2": { 37 | "events": [{ "schedule": "rate(5 minutes)" }], 38 | "handler": "handler.handler", 39 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 40 | "runtime": "nodejs18.x" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/fixtures/includes-all-provider-layer.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "include": ["layer-nodejs18x1", "layer-nodejs18x2"] 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs18x1": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs18.x" 34 | }, 35 | "layer-nodejs18x2": { 36 | "events": [{ "schedule": "rate(5 minutes)" }], 37 | "handler": "handler.handler", 38 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 39 | "runtime": "nodejs18.x" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/fixtures/trusted-account-key-included.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "trustedAccountKey": "${env:NEW_RELIC_TRUSTED_ACCOUNT_KEY}" 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs16.x" 34 | }, 35 | "layer-nodejs18x": { 36 | "events": [{ "schedule": "rate(5 minutes)" }], 37 | "handler": "handler.handler", 38 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 39 | "runtime": "nodejs18.x" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/fixtures/debug-log-level.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "logLevel": "error", 25 | "debug": true, 26 | "logEnabled": true 27 | } 28 | }, 29 | "disabledDeprecations": [], 30 | "functions": { 31 | "layer-nodejs16x": { 32 | "events": [{ "schedule": "rate(5 minutes)" }], 33 | "handler": "handler.handler", 34 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 35 | "runtime": "nodejs16.x" 36 | }, 37 | "layer-nodejs18x": { 38 | "events": [{ "schedule": "rate(5 minutes)" }], 39 | "handler": "handler.handler", 40 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 41 | "runtime": "nodejs18.x" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/fixtures/log-ingestion-via-extension.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "custom": { 20 | "newRelic": { 21 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 22 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 23 | "disableAutoSubscription": true, 24 | "logLevel": "debug", 25 | "enableIntegration": true, 26 | "enableFunctionLogs": true 27 | } 28 | }, 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [{ "schedule": "rate(5 minutes)" }], 32 | "handler": "handler.handler", 33 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 34 | "runtime": "nodejs16.x" 35 | }, 36 | "layer-nodejs18x": { 37 | "events": [{ "schedule": "rate(5 minutes)" }], 38 | "handler": "handler.handler", 39 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 40 | "runtime": "nodejs18.x" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/fixtures/provider-environment.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | }, 17 | "environment": { 18 | "NEW_RELIC_LOG_LEVEL": "error" 19 | } 20 | }, 21 | "plugins": ["serverless-newrelic-lambda-layers"], 22 | "configValidationMode": "warn", 23 | "custom": { 24 | "newRelic": { 25 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 26 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 27 | "logEnabled": true 28 | } 29 | }, 30 | "disabledDeprecations": [], 31 | "functions": { 32 | "layer-nodejs16x": { 33 | "events": [{ "schedule": "rate(5 minutes)" }], 34 | "handler": "handler.handler", 35 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 36 | "runtime": "nodejs16.x" 37 | }, 38 | "layer-nodejs18x": { 39 | "events": [{ "schedule": "rate(5 minutes)" }], 40 | "handler": "handler.handler", 41 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 42 | "runtime": "nodejs18.x" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/fixtures/provider-environment-log-level.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | }, 17 | "environment": { 18 | "NEW_RELIC_LOG_LEVEL": "error" 19 | } 20 | }, 21 | "plugins": ["serverless-newrelic-lambda-layers"], 22 | "configValidationMode": "warn", 23 | "custom": { 24 | "newRelic": { 25 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 26 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 27 | "logLevel": "trace", 28 | "logEnabled": true 29 | } 30 | }, 31 | "disabledDeprecations": [], 32 | "functions": { 33 | "layer-nodejs16x": { 34 | "events": [{ "schedule": "rate(5 minutes)" }], 35 | "handler": "handler.handler", 36 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 37 | "runtime": "nodejs16.x" 38 | }, 39 | "layer-nodejs18x": { 40 | "events": [{ "schedule": "rate(5 minutes)" }], 41 | "handler": "handler.handler", 42 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 43 | "runtime": "nodejs18.x" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/java/java-example.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/ci-workflow.yml: -------------------------------------------------------------------------------- 1 | name: NR Serverless Plugin CI 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | jobs: 6 | lint: 7 | name: Lint 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [lts/*] 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Use Node.js ${{ matrix.node-version }} 16 | uses: actions/setup-node@v3 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - name: Install Dependencies 20 | run: npm ci 21 | - name: Run Linting 22 | run: npm run lint 23 | - name: Inspect Lockfile 24 | run: npm run lint:lockfile 25 | test: 26 | name: Snapshot Test 27 | runs-on: ubuntu-latest 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | node-version: [lts/*] 32 | steps: 33 | - uses: actions/checkout@v3 34 | - name: Use Node.js ${{ matrix.node-version }} 35 | uses: actions/setup-node@v3 36 | with: 37 | node-version: ${{ matrix.node-version }} 38 | - name: Install Dependencies 39 | run: npm ci 40 | - name: Build 41 | run: npm run build 42 | - name: Run Snapshot Tests 43 | run: npm test 44 | - name: Upload Unit Test Coverage 45 | uses: codecov/codecov-action@v5.4.2 46 | with: 47 | token: ${{ secrets.CODECOV_TOKEN }} 48 | file: ./coverage/lcov.info 49 | fail_ci_if_error: true 50 | flags: unit-tests 51 | -------------------------------------------------------------------------------- /examples/nodejs/serverless.yml: -------------------------------------------------------------------------------- 1 | service: newrelic-lambda-layers-nodejs-example 2 | 3 | provider: 4 | name: aws 5 | stage: prod 6 | region: us-east-1 7 | stackTags: 8 | environment: us-testing 9 | owning_team: LAMBDA 10 | product: aws-lambda 11 | tags: 12 | environment: us-testing 13 | owning_team: LAMBDA 14 | product: aws-lambda 15 | 16 | plugins: 17 | - serverless-newrelic-lambda-layers 18 | 19 | custom: 20 | newRelic: 21 | accountId: ${env:NEW_RELIC_ACCOUNT_ID} 22 | apiKey: ${env:NEW_RELIC_PERSONAL_API_KEY} 23 | logLevel: debug 24 | 25 | functions: 26 | layer-nodejs16x: 27 | handler: handler.handler 28 | package: 29 | exclude: 30 | - ./** 31 | include: 32 | - handler.js 33 | runtime: nodejs16.x 34 | 35 | layer-nodejs18x: 36 | handler: handler.handler 37 | package: 38 | exclude: 39 | - ./** 40 | include: 41 | - handler.js 42 | runtime: nodejs18.x 43 | 44 | layer-nodejs20x: 45 | handler: handler.handler 46 | package: 47 | exclude: 48 | - ./** 49 | include: 50 | - handler.js 51 | runtime: nodejs20.x 52 | 53 | layer-nodejs22x: 54 | handler: handler.handler 55 | package: 56 | exclude: 57 | - ./** 58 | include: 59 | - handler.js 60 | runtime: nodejs22.x 61 | 62 | layer-nodejs24x: 63 | handler: handler.handler 64 | package: 65 | exclude: 66 | - ./** 67 | include: 68 | - handler.js 69 | runtime: nodejs24.x -------------------------------------------------------------------------------- /tests/fixtures/license-key-null.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": [ 19 | "serverless-newrelic-lambda-layers" 20 | ], 21 | "custom": { 22 | "newRelic": { 23 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 24 | "apiKey": null, 25 | "logLevel": "debug" 26 | } 27 | }, 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [ 31 | { 32 | "schedule": "rate(5 minutes)" 33 | } 34 | ], 35 | "handler": "handler.handler", 36 | "package": { 37 | "exclude": [ 38 | "./**" 39 | ], 40 | "include": [ 41 | "handler.js" 42 | ] 43 | }, 44 | "runtime": "nodejs16.x" 45 | }, 46 | "layer-nodejs18x": { 47 | "events": [ 48 | { 49 | "schedule": "rate(5 minutes)" 50 | } 51 | ], 52 | "handler": "handler.handler", 53 | "package": { 54 | "exclude": [ 55 | "./**" 56 | ], 57 | "include": [ 58 | "handler.js" 59 | ] 60 | }, 61 | "runtime": "nodejs18.x" 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/fixtures/arm64.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "architecture": "arm64", 8 | "stackTags": { 9 | "environment": "us-testing", 10 | "owning_team": "LAMBDA", 11 | "product": "aws-lambda" 12 | }, 13 | "tags": { 14 | "environment": "us-testing", 15 | "owning_team": "LAMBDA", 16 | "product": "aws-lambda" 17 | } 18 | }, 19 | "plugins": [ 20 | "serverless-newrelic-lambda-layers" 21 | ], 22 | "custom": { 23 | "newRelic": { 24 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 25 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 26 | "logLevel": "debug" 27 | } 28 | }, 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [ 32 | { 33 | "schedule": "rate(5 minutes)" 34 | } 35 | ], 36 | "handler": "handler.handler", 37 | "package": { 38 | "exclude": [ 39 | "./**" 40 | ], 41 | "include": [ 42 | "handler.js" 43 | ] 44 | }, 45 | "runtime": "nodejs16.x" 46 | }, 47 | "layer-nodejs18x": { 48 | "events": [ 49 | { 50 | "schedule": "rate(5 minutes)" 51 | } 52 | ], 53 | "handler": "handler.handler", 54 | "package": { 55 | "exclude": [ 56 | "./**" 57 | ], 58 | "include": [ 59 | "handler.js" 60 | ] 61 | }, 62 | "runtime": "nodejs18.x" 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/fixtures/arm64-unsupported.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "ap-south-2", 7 | "architecture": "arm64", 8 | "stackTags": { 9 | "environment": "us-testing", 10 | "owning_team": "LAMBDA", 11 | "product": "aws-lambda" 12 | }, 13 | "tags": { 14 | "environment": "us-testing", 15 | "owning_team": "LAMBDA", 16 | "product": "aws-lambda" 17 | } 18 | }, 19 | "plugins": [ 20 | "serverless-newrelic-lambda-layers" 21 | ], 22 | "custom": { 23 | "newRelic": { 24 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 25 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 26 | "logLevel": "debug" 27 | } 28 | }, 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [ 32 | { 33 | "schedule": "rate(5 minutes)" 34 | } 35 | ], 36 | "handler": "handler.handler", 37 | "package": { 38 | "exclude": [ 39 | "./**" 40 | ], 41 | "include": [ 42 | "handler.js" 43 | ] 44 | }, 45 | "runtime": "nodejs16.x" 46 | }, 47 | "layer-nodejs18x": { 48 | "events": [ 49 | { 50 | "schedule": "rate(5 minutes)" 51 | } 52 | ], 53 | "handler": "handler.handler", 54 | "package": { 55 | "exclude": [ 56 | "./**" 57 | ], 58 | "include": [ 59 | "handler.js" 60 | ] 61 | }, 62 | "runtime": "nodejs18.x" 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/fixtures/license-key-null.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": null, 7 | "logLevel": "debug" 8 | } 9 | }, 10 | "disabledDeprecations": [], 11 | "functions": { 12 | "layer-nodejs16x": { 13 | "events": [ 14 | { 15 | "schedule": "rate(5 minutes)" 16 | } 17 | ], 18 | "handler": "handler.handler", 19 | "package": { 20 | "exclude": [ 21 | "./**" 22 | ], 23 | "include": [ 24 | "handler.js" 25 | ] 26 | }, 27 | "runtime": "nodejs16.x" 28 | }, 29 | "layer-nodejs18x": { 30 | "events": [ 31 | { 32 | "schedule": "rate(5 minutes)" 33 | } 34 | ], 35 | "handler": "handler.handler", 36 | "package": { 37 | "exclude": [ 38 | "./**" 39 | ], 40 | "include": [ 41 | "handler.js" 42 | ] 43 | }, 44 | "runtime": "nodejs18.x" 45 | } 46 | }, 47 | "plugins": [ 48 | "serverless-newrelic-lambda-layers" 49 | ], 50 | "provider": { 51 | "name": "aws", 52 | "region": "us-east-1", 53 | "stackTags": { 54 | "environment": "us-testing", 55 | "owning_team": "LAMBDA", 56 | "product": "aws-lambda" 57 | }, 58 | "stage": "prod", 59 | "tags": { 60 | "environment": "us-testing", 61 | "owning_team": "LAMBDA", 62 | "product": "aws-lambda" 63 | } 64 | }, 65 | "service": "newrelic-lambda-layers-nodejs-example" 66 | } 67 | -------------------------------------------------------------------------------- /tests/fixtures/manual-wrapping.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "logLevel": "debug", 8 | "manualWrapping": true 9 | } 10 | }, 11 | "disabledDeprecations": [], 12 | "functions": { 13 | "layer-nodejs18x": { 14 | "environment": { 15 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 16 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 17 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 18 | "NEW_RELIC_NO_CONFIG_FILE": "true", 19 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 20 | }, 21 | "events": [ 22 | { 23 | "schedule": "rate(5 minutes)" 24 | } 25 | ], 26 | "handler": "handler.handler", 27 | "package": { 28 | "exclude": [ 29 | "./**" 30 | ], 31 | "include": [ 32 | "handler.js" 33 | ] 34 | }, 35 | "runtime": "nodejs18.x" 36 | } 37 | }, 38 | "plugins": [ 39 | "serverless-newrelic-lambda-layers" 40 | ], 41 | "provider": { 42 | "layers": [ 43 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 44 | ], 45 | "name": "aws", 46 | "region": "us-east-1", 47 | "stackTags": { 48 | "environment": "us-testing", 49 | "owning_team": "LAMBDA", 50 | "product": "aws-lambda" 51 | }, 52 | "stage": "prod", 53 | "tags": { 54 | "environment": "us-testing", 55 | "owning_team": "LAMBDA", 56 | "product": "aws-lambda" 57 | } 58 | }, 59 | "service": "newrelic-lambda-layers-nodejs-example" 60 | } 61 | -------------------------------------------------------------------------------- /.github/workflows/validate-pr.yml: -------------------------------------------------------------------------------- 1 | name: Validate Pull Request 2 | 3 | permissions: 4 | pull-requests: write 5 | 6 | on: 7 | pull_request: 8 | types: 9 | - opened 10 | - edited 11 | - synchronize 12 | 13 | jobs: 14 | validate-pr: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Pull Request Title is Conventional 18 | id: lint_pr_title 19 | uses: amannn/action-semantic-pull-request@v5 20 | with: 21 | # Recommended Prefixes from https://github.com/conventional-changelog/commitlint/blob/master/%40commitlint/config-conventional/README.md#type-enum 22 | types: | 23 | build 24 | chore 25 | ci 26 | docs 27 | feat 28 | fix 29 | perf 30 | refactor 31 | revert 32 | security 33 | style 34 | test 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | - if: failure() 38 | name: Add PR comment if failed 39 | uses: marocchino/sticky-pull-request-comment@v2 40 | with: 41 | header: pr-title-lint-error 42 | message: | 43 | Thank you for your contribution! We require all PR titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/). 44 | Please update your PR title with the appropriate type and we'll try again! 45 | ``` 46 | ${{ steps.lint_pr_title.outputs.error_message}} 47 | ``` 48 | - if: success() 49 | name: Remove PR comment if valid 50 | uses: marocchino/sticky-pull-request-comment@v2 51 | with: 52 | header: pr-title-lint-error 53 | delete: true -------------------------------------------------------------------------------- /tests/fixtures/include.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "include": ["layer-nodejs18x"] 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "handler.handler", 32 | "package": { "exclude": ["./**"], "include": ["handler.js"] }, 33 | "runtime": "nodejs16.x" 34 | }, 35 | "layer-nodejs18x": { 36 | "environment": { 37 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 38 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 39 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 40 | "NEW_RELIC_NO_CONFIG_FILE": "true", 41 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 42 | }, 43 | "events": [{ "schedule": "rate(5 minutes)" }], 44 | "handler": "newrelic-lambda-wrapper.handler", 45 | "layers": [ 46 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 47 | ], 48 | "package": { "exclude": [ 49 | "./**", 50 | "!newrelic-wrapper-helper.js" 51 | ], "include": ["handler.js"] }, 52 | "runtime": "nodejs18.x" 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/python/serverless.yml: -------------------------------------------------------------------------------- 1 | service: newrelic-lambda-layers-python-example 2 | 3 | provider: 4 | name: aws 5 | stage: prod 6 | region: us-east-1 7 | stackTags: 8 | environment: us-testing 9 | owning_team: LAMBDA 10 | product: aws-lambda 11 | tags: 12 | environment: us-testing 13 | owning_team: LAMBDA 14 | product: aws-lambda 15 | 16 | plugins: 17 | - serverless-newrelic-lambda-layers 18 | 19 | custom: 20 | newRelic: 21 | accountId: ${env:NEW_RELIC_ACCOUNT_ID} 22 | apiKey: ${env:NEW_RELIC_PERSONAL_API_KEY} 23 | 24 | debug: true 25 | 26 | functions: 27 | 28 | layer-python38: 29 | handler: handler.handler 30 | package: 31 | exclude: 32 | - ./** 33 | include: 34 | - handler.py 35 | runtime: python3.8 36 | 37 | layer-python39: 38 | handler: handler.handler 39 | package: 40 | exclude: 41 | - ./** 42 | include: 43 | - handler.py 44 | runtime: python3.9 45 | 46 | layer-python310: 47 | handler: handler.handler 48 | package: 49 | exclude: 50 | - ./** 51 | include: 52 | - handler.py 53 | runtime: python3.10 54 | 55 | layer-python311: 56 | handler: handler.handler 57 | package: 58 | exclude: 59 | - ./** 60 | include: 61 | - handler.py 62 | runtime: python3.11 63 | 64 | layer-python312: 65 | handler: handler.handler 66 | package: 67 | exclude: 68 | - ./** 69 | include: 70 | - handler.py 71 | runtime: python3.12 72 | 73 | layer-python313: 74 | handler: handler.handler 75 | package: 76 | exclude: 77 | - ./** 78 | include: 79 | - handler.py 80 | runtime: python3.13 81 | 82 | layer-python314: 83 | handler: handler.handler 84 | package: 85 | exclude: 86 | - ./** 87 | include: 88 | - handler.py 89 | runtime: python3.14 90 | -------------------------------------------------------------------------------- /templates/nr-license-key-secret.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Parameters: 3 | LicenseKey: 4 | Type: String 5 | Description: The New Relic account license key 6 | NoEcho: true 7 | SecretName: 8 | Type: String 9 | Description: The friendly name for the license key secret 10 | Default: NEW_RELIC_LICENSE_KEY 11 | PolicyName: 12 | Type: String 13 | Description: Policy name of the policy to use to allow access to the license key secret. 14 | Default: NewRelic-ViewLicenseKey 15 | LicenseKeySecretExportName: 16 | Type: String 17 | Default: NewRelic-LicenseKeySecretARN 18 | ViewPolicyExportName: 19 | Type: String 20 | Default: NewRelic-ViewLicenseKeyPolicyARN 21 | Region: 22 | Type: String 23 | 24 | Resources: 25 | LicenseKeySecret: 26 | Type: 'AWS::SecretsManager::Secret' 27 | Properties: 28 | Description: The New Relic license key, for sending telemetry 29 | Name: !Sub "${SecretName}" 30 | SecretString: !Sub '{ "LicenseKey": "${LicenseKey}" }' 31 | ViewNewRelicLicenseKeyPolicy: 32 | Type: 'AWS::IAM::ManagedPolicy' 33 | Properties: 34 | ManagedPolicyName: !Sub 35 | - ${PolicyName}-${Region} 36 | - { PolicyName: !Ref PolicyName, Region: !Ref Region } 37 | PolicyDocument: 38 | Version: 2012-10-17 39 | Statement: 40 | - Effect: Allow 41 | Action: 42 | - 'secretsmanager:GetSecretValue' 43 | Resource: !Ref LicenseKeySecret 44 | 45 | Outputs: 46 | LicenseKeySecretARN: 47 | Description: The ARN of the LicenseKey Secret 48 | Value: !Ref LicenseKeySecret 49 | Export: 50 | Name: !Sub "${AWS::StackName}-${LicenseKeySecretExportName}" 51 | ViewPolicyARN: 52 | Description: The ARN of the LicenseKey Secret's view policy 53 | Value: !Ref ViewNewRelicLicenseKeyPolicy 54 | Export: 55 | Name: !Sub "${AWS::StackName}-${ViewPolicyExportName}" 56 | -------------------------------------------------------------------------------- /tests/fixtures/arm64-unsupported.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "logLevel": "debug" 8 | } 9 | }, 10 | "disabledDeprecations": [], 11 | "functions": { 12 | "layer-nodejs16x": { 13 | "handler": "newrelic-lambda-wrapper.handler", 14 | "environment": { 15 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 16 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 17 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 18 | "NEW_RELIC_NO_CONFIG_FILE": "true", 19 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 20 | }, 21 | "events": [ 22 | { 23 | "schedule": "rate(5 minutes)" 24 | } 25 | ], 26 | "package": { 27 | "exclude": [ 28 | "./**", 29 | "!newrelic-wrapper-helper.js" 30 | ], 31 | "include": [ 32 | "handler.js" 33 | ] 34 | }, 35 | "runtime": "nodejs16.x", 36 | "layers": [ 37 | "arn:aws:lambda:ap-south-2:451483290750:layer:NewRelicNodeJS16XARM64:2" 38 | ] 39 | }, 40 | "layer-nodejs18x": { 41 | "events": [ 42 | { 43 | "schedule": "rate(5 minutes)" 44 | } 45 | ], 46 | "handler": "handler.handler", 47 | "package": { 48 | "exclude": [ 49 | "./**" 50 | ], 51 | "include": [ 52 | "handler.js" 53 | ] 54 | }, 55 | "runtime": "nodejs18.x" 56 | } 57 | }, 58 | "plugins": [ 59 | "serverless-newrelic-lambda-layers" 60 | ], 61 | "provider": { 62 | "architecture": "arm64", 63 | "name": "aws", 64 | "region": "ap-south-2", 65 | "stackTags": { 66 | "environment": "us-testing", 67 | "owning_team": "LAMBDA", 68 | "product": "aws-lambda" 69 | }, 70 | "stage": "prod", 71 | "tags": { 72 | "environment": "us-testing", 73 | "owning_team": "LAMBDA", 74 | "product": "aws-lambda" 75 | } 76 | }, 77 | "service": "newrelic-lambda-layers-nodejs-example" 78 | } 79 | -------------------------------------------------------------------------------- /tests/fixtures/provider-layer.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "layers": [ 5 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 6 | ], 7 | "name": "aws", 8 | "stage": "prod", 9 | "region": "us-east-1", 10 | "stackTags": { 11 | "environment": "us-testing", 12 | "owning_team": "LAMBDA", 13 | "product": "aws-lambda" 14 | }, 15 | "tags": { 16 | "environment": "us-testing", 17 | "owning_team": "LAMBDA", 18 | "product": "aws-lambda" 19 | } 20 | }, 21 | "plugins": ["serverless-newrelic-lambda-layers"], 22 | "configValidationMode": "warn", 23 | "custom": { 24 | "newRelic": { 25 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 26 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}" 27 | } 28 | }, 29 | "disabledDeprecations": [], 30 | "functions": { 31 | "layer-nodejs18x1": { 32 | "environment": { 33 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 34 | "NEW_RELIC_APP_NAME": "layer-nodejs18x1", 35 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 36 | "NEW_RELIC_NO_CONFIG_FILE": "true", 37 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 38 | }, 39 | "events": [{ "schedule": "rate(5 minutes)" }], 40 | "handler": "newrelic-lambda-wrapper.handler", 41 | "package": { 42 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 43 | "include": ["handler.js"] 44 | }, 45 | "runtime": "nodejs18.x" 46 | }, 47 | "layer-nodejs18x2": { 48 | "environment": { 49 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 50 | "NEW_RELIC_APP_NAME": "layer-nodejs18x2", 51 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 52 | "NEW_RELIC_NO_CONFIG_FILE": "true", 53 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 54 | }, 55 | "events": [{ "schedule": "rate(5 minutes)" }], 56 | "handler": "newrelic-lambda-wrapper.handler", 57 | "package": { 58 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 59 | "include": ["handler.js"] 60 | }, 61 | "runtime": "nodejs18.x" 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/fixtures/node-versions.input.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": [ 19 | "serverless-newrelic-lambda-layers" 20 | ], 21 | "custom": { 22 | "newRelic": { 23 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 24 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}" 25 | } 26 | }, 27 | "functions": { 28 | "layer-nodejs16x": { 29 | "events": [ 30 | { 31 | "schedule": "rate(5 minutes)" 32 | } 33 | ], 34 | "handler": "handler.handler", 35 | "package": { 36 | "exclude": [ 37 | "./**" 38 | ], 39 | "include": [ 40 | "handler.js" 41 | ] 42 | }, 43 | "runtime": "nodejs16.x" 44 | }, 45 | "layer-nodejs18x": { 46 | "events": [ 47 | { 48 | "schedule": "rate(5 minutes)" 49 | } 50 | ], 51 | "handler": "handler.handler", 52 | "package": { 53 | "exclude": [ 54 | "./**" 55 | ], 56 | "include": [ 57 | "handler.js" 58 | ] 59 | }, 60 | "runtime": "nodejs18.x" 61 | }, 62 | "layer-nodejs20x": { 63 | "events": [ 64 | { 65 | "schedule": "rate(5 minutes)" 66 | } 67 | ], 68 | "handler": "handler.handler", 69 | "package": { 70 | "exclude": [ 71 | "./**" 72 | ], 73 | "include": [ 74 | "handler.js" 75 | ] 76 | }, 77 | "runtime": "nodejs20.x" 78 | }, 79 | "layer-nodejs22x": { 80 | "events": [ 81 | { 82 | "schedule": "rate(5 minutes)" 83 | } 84 | ], 85 | "handler": "handler.handler", 86 | "package": { 87 | "exclude": [ 88 | "./**" 89 | ], 90 | "include": [ 91 | "handler.js" 92 | ] 93 | }, 94 | "runtime": "nodejs22.x" 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /tests/fixtures/includes-all-provider-layer.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "layers": [ 5 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 6 | ], 7 | "name": "aws", 8 | "stage": "prod", 9 | "region": "us-east-1", 10 | "stackTags": { 11 | "environment": "us-testing", 12 | "owning_team": "LAMBDA", 13 | "product": "aws-lambda" 14 | }, 15 | "tags": { 16 | "environment": "us-testing", 17 | "owning_team": "LAMBDA", 18 | "product": "aws-lambda" 19 | } 20 | }, 21 | "plugins": ["serverless-newrelic-lambda-layers"], 22 | "configValidationMode": "warn", 23 | "custom": { 24 | "newRelic": { 25 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 26 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 27 | "include": ["layer-nodejs18x1", "layer-nodejs18x2"] 28 | } 29 | }, 30 | "disabledDeprecations": [], 31 | "functions": { 32 | "layer-nodejs18x1": { 33 | "environment": { 34 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 35 | "NEW_RELIC_APP_NAME": "layer-nodejs18x1", 36 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 37 | "NEW_RELIC_NO_CONFIG_FILE": "true", 38 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 39 | }, 40 | "events": [{ "schedule": "rate(5 minutes)" }], 41 | "handler": "newrelic-lambda-wrapper.handler", 42 | "package": { 43 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 44 | "include": ["handler.js"] 45 | }, 46 | "runtime": "nodejs18.x" 47 | }, 48 | "layer-nodejs18x2": { 49 | "environment": { 50 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 51 | "NEW_RELIC_APP_NAME": "layer-nodejs18x2", 52 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 53 | "NEW_RELIC_NO_CONFIG_FILE": "true", 54 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 55 | }, 56 | "events": [{ "schedule": "rate(5 minutes)" }], 57 | "handler": "newrelic-lambda-wrapper.handler", 58 | "package": { 59 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 60 | "include": ["handler.js"] 61 | }, 62 | "runtime": "nodejs18.x" 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/fixtures/trusted-account-key-excluded.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}" 24 | } 25 | }, 26 | "disabledDeprecations": [], 27 | "functions": { 28 | "layer-nodejs16x": { 29 | "events": [{ "schedule": "rate(5 minutes)" }], 30 | "handler": "newrelic-lambda-wrapper.handler", 31 | "layers": [ 32 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 33 | ], 34 | "package": { 35 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 36 | "include": ["handler.js"] 37 | }, 38 | "runtime": "nodejs16.x", 39 | "environment": { 40 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 41 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 42 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 43 | "NEW_RELIC_NO_CONFIG_FILE": "true", 44 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 45 | } 46 | }, 47 | "layer-nodejs18x": { 48 | "events": [{ "schedule": "rate(5 minutes)" }], 49 | "handler": "newrelic-lambda-wrapper.handler", 50 | "layers": [ 51 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 52 | ], 53 | "package": { 54 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 55 | "include": ["handler.js"] 56 | }, 57 | "runtime": "nodejs18.x", 58 | "environment": { 59 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 60 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 61 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 62 | "NEW_RELIC_NO_CONFIG_FILE": "true", 63 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/fixtures/ingest-key-only.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "ingestKey": "test-ingest-key", 24 | "logLevel": "debug" 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "newrelic-lambda-wrapper.handler", 32 | "package": { 33 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 34 | "include": ["handler.js"] 35 | }, 36 | "runtime": "nodejs16.x", 37 | "environment": { 38 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 39 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 40 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 41 | "NEW_RELIC_NO_CONFIG_FILE": "true", 42 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 43 | 44 | }, 45 | "layers": [ 46 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 47 | ] 48 | }, 49 | "layer-nodejs18x": { 50 | "events": [{ "schedule": "rate(5 minutes)" }], 51 | "handler": "newrelic-lambda-wrapper.handler", 52 | "package": { 53 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 54 | "include": ["handler.js"] 55 | }, 56 | "runtime": "nodejs18.x", 57 | "environment": { 58 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 59 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 60 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 61 | "NEW_RELIC_NO_CONFIG_FILE": "true", 62 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 63 | 64 | }, 65 | "layers": [ 66 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 67 | ] 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /tests/fixtures/stage-included.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "dev", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "stages": ["dev", "prod"] 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "newrelic-lambda-wrapper.handler", 32 | "layers": [ 33 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 34 | ], 35 | "package": { 36 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 37 | "include": ["handler.js"] 38 | }, 39 | "runtime": "nodejs16.x", 40 | "environment": { 41 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 42 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 43 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 44 | "NEW_RELIC_NO_CONFIG_FILE": "true", 45 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 46 | } 47 | }, 48 | "layer-nodejs18x": { 49 | "events": [{ "schedule": "rate(5 minutes)" }], 50 | "handler": "newrelic-lambda-wrapper.handler", 51 | "layers": [ 52 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 53 | ], 54 | "package": { 55 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 56 | "include": ["handler.js"] 57 | }, 58 | "runtime": "nodejs18.x", 59 | "environment": { 60 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 61 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 62 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 63 | "NEW_RELIC_NO_CONFIG_FILE": "true", 64 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/fixtures/log-disabled.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "logLevel": "error", 25 | "debug": true 26 | } 27 | }, 28 | "disabledDeprecations": [], 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [{ "schedule": "rate(5 minutes)" }], 32 | "handler": "newrelic-lambda-wrapper.handler", 33 | "layers": [ 34 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 35 | ], 36 | "package": { 37 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 38 | "include": ["handler.js"] 39 | }, 40 | "runtime": "nodejs16.x", 41 | "environment": { 42 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 43 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 44 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 45 | "NEW_RELIC_NO_CONFIG_FILE": "true", 46 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 47 | } 48 | }, 49 | "layer-nodejs18x": { 50 | "events": [{ "schedule": "rate(5 minutes)" }], 51 | "handler": "newrelic-lambda-wrapper.handler", 52 | "layers": [ 53 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 54 | ], 55 | "package": { 56 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 57 | "include": ["handler.js"] 58 | }, 59 | "runtime": "nodejs18.x", 60 | "environment": { 61 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 62 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 63 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 64 | "NEW_RELIC_NO_CONFIG_FILE": "true", 65 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/fixtures/api-and-ingest-key.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "test-api-key", 24 | "ingestKey": "test-ingest-key", 25 | "logLevel": "debug" 26 | } 27 | }, 28 | "disabledDeprecations": [], 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [{ "schedule": "rate(5 minutes)" }], 32 | "handler": "newrelic-lambda-wrapper.handler", 33 | "package": { 34 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 35 | "include": ["handler.js"] 36 | }, 37 | "runtime": "nodejs16.x", 38 | "environment": { 39 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 40 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 41 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 42 | "NEW_RELIC_NO_CONFIG_FILE": "true", 43 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 44 | 45 | }, 46 | "layers": [ 47 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 48 | ] 49 | }, 50 | "layer-nodejs18x": { 51 | "events": [{ "schedule": "rate(5 minutes)" }], 52 | "handler": "newrelic-lambda-wrapper.handler", 53 | "package": { 54 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 55 | "include": ["handler.js"] 56 | }, 57 | "runtime": "nodejs18.x", 58 | "environment": { 59 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 60 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 61 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 62 | "NEW_RELIC_NO_CONFIG_FILE": "true", 63 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 64 | }, 65 | "layers": [ 66 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 67 | ] 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-newrelic-lambda-layers", 3 | "version": "5.13.0", 4 | "description": "Serverless plugin for NewRelic APM AWS Lambda layers.", 5 | "main": "dist/index.js", 6 | "files": [ 7 | "dist", 8 | "package.json", 9 | "README.md", 10 | "templates" 11 | ], 12 | "scripts": { 13 | "build": "rm -rf dist && tsc", 14 | "test": "jest", 15 | "test:watch": "jest --watchAll", 16 | "lint": "tslint -c tslint.json 'src/**/*.ts'", 17 | "lint:fix": "tslint --fix -c tslint.json 'src/**/*.ts'", 18 | "lint:lockfile": "lockfile-lint --path package-lock.json --type npm --allowed-hosts npm --validate-https --validate-integrity", 19 | "generate:test:case": "yaml2json examples/nodejs/serverless.yml > tests/fixtures/example.input.service.json", 20 | "prepare": "husky install" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/newrelic/serverless-newrelic-lambda-layers.git" 25 | }, 26 | "author": "New Relic", 27 | "license": "Apache-2.0", 28 | "bugs": { 29 | "url": "https://github.com/newrelic/serverless-newrelic-lambda-layers/issues" 30 | }, 31 | "homepage": "https://github.com/newrelic/serverless-newrelic-lambda-layers#readme", 32 | "devDependencies": { 33 | "@types/fs-extra": "^9.0.13", 34 | "@types/jest": "^29.2.0", 35 | "@types/lodash": "^4.14.186", 36 | "@types/node": "^18.11.6", 37 | "@types/node-fetch": "2.6.2", 38 | "@types/ramda": "^0.28.18", 39 | "get-installed-path": "^4.0.8", 40 | "husky": "^8.0.1", 41 | "jest": "^29.2.2", 42 | "lockfile-lint": "^4.9.6", 43 | "prettier": "^2.7.1", 44 | "ramda": "^0.28.0", 45 | "ts-jest": "^29.0.3", 46 | "tslint": "^6.1.3", 47 | "tslint-config-prettier": "^1.18.0", 48 | "tslint-plugin-prettier": "^2.3.0", 49 | "typescript": "^4.8.4", 50 | "yamljs": "^0.3.0" 51 | }, 52 | "peerDependencies": { 53 | "@types/serverless": "^3.12.7", 54 | "https-proxy-agent": "^5.0.0", 55 | "lodash": "^4.17.21", 56 | "node-fetch": "^2.6.7", 57 | "path": "^0.12.7", 58 | "semver": "^7.5.4", 59 | "serverless": "4.x || 3.x" 60 | }, 61 | "keywords": [ 62 | "lambda", 63 | "serverless", 64 | "sls", 65 | "agent", 66 | "analytics", 67 | "metrics", 68 | "telemetry", 69 | "tracing", 70 | "distributed tracing", 71 | "layers" 72 | ], 73 | "engines": { 74 | "node": ">=16.0.0" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are always welcome. Before contributing please read the 4 | [code of conduct](./CODE_OF_CONDUCT.md) and [search the issue tracker](issues); your issue may have already been discussed or fixed in `master`. To contribute, 5 | [fork](https://help.github.com/articles/fork-a-repo/) this repository, commit your changes, and [send a Pull Request](https://help.github.com/articles/using-pull-requests/). 6 | 7 | Note that our [code of conduct](./CODE_OF_CONDUCT.md) applies to all platforms and venues related to this project; please follow it in all your interactions with the project and its participants. 8 | 9 | ## Feature Requests 10 | 11 | Feature requests should be submitted in the [Issue tracker](../../issues), with a description of the expected behavior & use case, where they’ll remain closed until sufficient interest, [e.g. :+1: reactions](https://help.github.com/articles/about-discussions-in-issues-and-pull-requests/), has been [shown by the community](../../issues?q=label%3A%22votes+needed%22+sort%3Areactions-%2B1-desc). 12 | Before submitting an Issue, please search for similar ones in the 13 | [closed issues](../../issues?q=is%3Aissue+is%3Aclosed+label%3Aenhancement). 14 | 15 | ## Pull Requests 16 | 17 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a build. 18 | 2. Increase the version numbers in any examples files and the README.md to the new version that this Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 19 | 3. You may merge the Pull Request in once you have the sign-off of two other developers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. 20 | 21 | ## Contributor License Agreement 22 | 23 | Keep in mind that when you submit your Pull Request, you'll need to sign the CLA via the click-through using CLA-Assistant. If you'd like to execute our corporate CLA, or if you have any questions, please drop us an email at opensource@newrelic.com. 24 | 25 | For more information about CLAs, please check out Alex Russell’s excellent post, 26 | [“Why Do I Need to Sign This?”](https://infrequently.org/2008/06/why-do-i-need-to-sign-this/). 27 | 28 | ## Slack 29 | 30 | For contributors and maintainers of open source projects hosted by New Relic, we host a public Slack with a channel dedicated to this project. If you are contributing to this project, you're welcome to request access to that community space. 31 | -------------------------------------------------------------------------------- /tests/fixtures/trusted-account-key-included.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "trustedAccountKey": "${env:NEW_RELIC_TRUSTED_ACCOUNT_KEY}" 25 | } 26 | }, 27 | "disabledDeprecations": [], 28 | "functions": { 29 | "layer-nodejs16x": { 30 | "events": [{ "schedule": "rate(5 minutes)" }], 31 | "handler": "newrelic-lambda-wrapper.handler", 32 | "layers": [ 33 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 34 | ], 35 | "package": { 36 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 37 | "include": ["handler.js"] 38 | }, 39 | "runtime": "nodejs16.x", 40 | "environment": { 41 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 42 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 43 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 44 | "NEW_RELIC_NO_CONFIG_FILE": "true", 45 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_TRUSTED_ACCOUNT_KEY}" 46 | } 47 | }, 48 | "layer-nodejs18x": { 49 | "events": [{ "schedule": "rate(5 minutes)" }], 50 | "handler": "newrelic-lambda-wrapper.handler", 51 | "layers": [ 52 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 53 | ], 54 | "package": { 55 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 56 | "include": ["handler.js"] 57 | }, 58 | "runtime": "nodejs18.x", 59 | "environment": { 60 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 61 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 62 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 63 | "NEW_RELIC_NO_CONFIG_FILE": "true", 64 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_TRUSTED_ACCOUNT_KEY}" 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/fixtures/function-has-layers.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "layers": [ 5 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 6 | ], 7 | "name": "aws", 8 | "stage": "prod", 9 | "region": "us-east-1", 10 | "stackTags": { 11 | "environment": "us-testing", 12 | "owning_team": "LAMBDA", 13 | "product": "aws-lambda" 14 | }, 15 | "tags": { 16 | "environment": "us-testing", 17 | "owning_team": "LAMBDA", 18 | "product": "aws-lambda" 19 | } 20 | }, 21 | "plugins": ["serverless-newrelic-lambda-layers"], 22 | "configValidationMode": "warn", 23 | "custom": { 24 | "newRelic": { 25 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 26 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 27 | "logLevel": "debug" 28 | } 29 | }, 30 | "disabledDeprecations": [], 31 | "functions": { 32 | "layer-nodejs18x1": { 33 | "environment": { 34 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 35 | "NEW_RELIC_APP_NAME": "layer-nodejs18x1", 36 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 37 | "NEW_RELIC_NO_CONFIG_FILE": "true", 38 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 39 | }, 40 | "events": [{ "schedule": "rate(5 minutes)" }], 41 | "handler": "newrelic-lambda-wrapper.handler", 42 | "package": { 43 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 44 | "include": ["handler.js"] 45 | }, 46 | "runtime": "nodejs18.x", 47 | "layers": [ 48 | "arn:aws:lambda:us-east-1:123456789012:layer:SomeOtherLayer:1", 49 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 50 | ] 51 | }, 52 | "layer-nodejs18x2": { 53 | "environment": { 54 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 55 | "NEW_RELIC_APP_NAME": "layer-nodejs18x2", 56 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 57 | "NEW_RELIC_NO_CONFIG_FILE": "true", 58 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 59 | }, 60 | "events": [{ "schedule": "rate(5 minutes)" }], 61 | "handler": "newrelic-lambda-wrapper.handler", 62 | "package": { 63 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 64 | "include": ["handler.js"] 65 | }, 66 | "runtime": "nodejs18.x" 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/fixtures/lambda-extension-enabled.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "logLevel": "debug" 8 | } 9 | }, 10 | "disabledDeprecations": [], 11 | "functions": { 12 | "layer-nodejs16x": { 13 | "environment": { 14 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 15 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 16 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 17 | "NEW_RELIC_NO_CONFIG_FILE": "true", 18 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 19 | }, 20 | "events": [ 21 | { 22 | "schedule": "rate(5 minutes)" 23 | } 24 | ], 25 | "handler": "newrelic-lambda-wrapper.handler", 26 | "layers": [ 27 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 28 | ], 29 | "package": { 30 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 31 | "include": ["handler.js"] 32 | }, 33 | "runtime": "nodejs16.x" 34 | }, 35 | "layer-nodejs18x": { 36 | "environment": { 37 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 38 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 39 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 40 | "NEW_RELIC_NO_CONFIG_FILE": "true", 41 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 42 | }, 43 | "events": [ 44 | { 45 | "schedule": "rate(5 minutes)" 46 | } 47 | ], 48 | "handler": "newrelic-lambda-wrapper.handler", 49 | "layers": [ 50 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 51 | ], 52 | "package": { 53 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 54 | "include": ["handler.js"] 55 | }, 56 | "runtime": "nodejs18.x" 57 | } 58 | }, 59 | "plugins": ["serverless-newrelic-lambda-layers"], 60 | "provider": { 61 | "name": "aws", 62 | "region": "us-east-1", 63 | "stackTags": { 64 | "environment": "us-testing", 65 | "owning_team": "LAMBDA", 66 | "product": "aws-lambda" 67 | }, 68 | "stage": "prod", 69 | "tags": { 70 | "environment": "us-testing", 71 | "owning_team": "LAMBDA", 72 | "product": "aws-lambda" 73 | } 74 | }, 75 | "service": "newrelic-lambda-layers-nodejs-example" 76 | } 77 | -------------------------------------------------------------------------------- /tests/fixtures/lambda-extension-disabled.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "enableExtension": false 8 | } 9 | }, 10 | "disabledDeprecations": [], 11 | "functions": { 12 | "layer-nodejs16x": { 13 | "environment": { 14 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 15 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 16 | "NEW_RELIC_LAMBDA_EXTENSION_ENABLED": "false", 17 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 18 | "NEW_RELIC_NO_CONFIG_FILE": "true", 19 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 20 | }, 21 | "events": [ 22 | { 23 | "schedule": "rate(5 minutes)" 24 | } 25 | ], 26 | "handler": "newrelic-lambda-wrapper.handler", 27 | "layers": [ 28 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 29 | ], 30 | "package": { 31 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 32 | "include": ["handler.js"] 33 | }, 34 | "runtime": "nodejs16.x" 35 | }, 36 | "layer-nodejs18x": { 37 | "environment": { 38 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 39 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 40 | "NEW_RELIC_LAMBDA_EXTENSION_ENABLED": "false", 41 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 42 | "NEW_RELIC_NO_CONFIG_FILE": "true", 43 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 44 | }, 45 | "events": [ 46 | { 47 | "schedule": "rate(5 minutes)" 48 | } 49 | ], 50 | "handler": "newrelic-lambda-wrapper.handler", 51 | "layers": [ 52 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 53 | ], 54 | "package": { 55 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 56 | "include": ["handler.js"] 57 | }, 58 | "runtime": "nodejs18.x" 59 | } 60 | }, 61 | "plugins": ["serverless-newrelic-lambda-layers"], 62 | "provider": { 63 | "name": "aws", 64 | "region": "us-east-1", 65 | "stackTags": { 66 | "environment": "us-testing", 67 | "owning_team": "LAMBDA", 68 | "product": "aws-lambda" 69 | }, 70 | "stage": "prod", 71 | "tags": { 72 | "environment": "us-testing", 73 | "owning_team": "LAMBDA", 74 | "product": "aws-lambda" 75 | } 76 | }, 77 | "service": "newrelic-lambda-layers-nodejs-example" 78 | } 79 | -------------------------------------------------------------------------------- /tests/fixtures/proxy.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "proxy": "http://myproxy.com:8080" 8 | } 9 | }, 10 | "disabledDeprecations": [], 11 | "functions": { 12 | "layer-nodejs16x": { 13 | "environment": { 14 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 15 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 16 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 17 | "NEW_RELIC_NO_CONFIG_FILE": "true", 18 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 19 | }, 20 | "events": [ 21 | { 22 | "schedule": "rate(5 minutes)" 23 | } 24 | ], 25 | "handler": "newrelic-lambda-wrapper.handler", 26 | "layers": [ 27 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 28 | ], 29 | "package": { 30 | "exclude": [ 31 | "./**", 32 | "!newrelic-wrapper-helper.js" 33 | ], 34 | "include": [ 35 | "handler.js" 36 | ] 37 | }, 38 | "runtime": "nodejs16.x" 39 | }, 40 | "layer-nodejs18x": { 41 | "environment": { 42 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 43 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 44 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 45 | "NEW_RELIC_NO_CONFIG_FILE": "true", 46 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 47 | }, 48 | "events": [ 49 | { 50 | "schedule": "rate(5 minutes)" 51 | } 52 | ], 53 | "handler": "newrelic-lambda-wrapper.handler", 54 | "layers": [ 55 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 56 | ], 57 | "package": { 58 | "exclude": [ 59 | "./**", 60 | "!newrelic-wrapper-helper.js" 61 | ], 62 | "include": [ 63 | "handler.js" 64 | ] 65 | }, 66 | "runtime": "nodejs18.x" 67 | } 68 | }, 69 | "plugins": ["serverless-newrelic-lambda-layers"], 70 | "provider": { 71 | "name": "aws", 72 | "region": "us-east-1", 73 | "stackTags": { 74 | "environment": "us-testing", 75 | "owning_team": "LAMBDA", 76 | "product": "aws-lambda" 77 | }, 78 | "stage": "prod", 79 | "tags": { 80 | "environment": "us-testing", 81 | "owning_team": "LAMBDA", 82 | "product": "aws-lambda" 83 | } 84 | }, 85 | "service": "newrelic-lambda-layers-nodejs-example" 86 | } 87 | -------------------------------------------------------------------------------- /tests/fixtures/debug.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "debug": true, 25 | "logEnabled": true 26 | } 27 | }, 28 | "disabledDeprecations": [], 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [{ "schedule": "rate(5 minutes)" }], 32 | "handler": "newrelic-lambda-wrapper.handler", 33 | "layers": [ 34 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 35 | ], 36 | "package": { 37 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 38 | "include": ["handler.js"] 39 | }, 40 | "runtime": "nodejs16.x", 41 | "environment": { 42 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 43 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 44 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 45 | "NEW_RELIC_LOG": "stdout", 46 | "NEW_RELIC_LOG_ENABLED": "true", 47 | "NEW_RELIC_LOG_LEVEL": "debug", 48 | "NEW_RELIC_NO_CONFIG_FILE": "true", 49 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 50 | } 51 | }, 52 | "layer-nodejs18x": { 53 | "events": [{ "schedule": "rate(5 minutes)" }], 54 | "handler": "newrelic-lambda-wrapper.handler", 55 | "layers": [ 56 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 57 | ], 58 | "package": { 59 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 60 | "include": ["handler.js"] 61 | }, 62 | "runtime": "nodejs18.x", 63 | "environment": { 64 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 65 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 66 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 67 | "NEW_RELIC_LOG": "stdout", 68 | "NEW_RELIC_LOG_ENABLED": "true", 69 | "NEW_RELIC_LOG_LEVEL": "debug", 70 | "NEW_RELIC_NO_CONFIG_FILE": "true", 71 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/fixtures/distributed-tracing-enabled.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "enableDistributedTracing": true, 8 | "logLevel": "debug" 9 | } 10 | }, 11 | "disabledDeprecations": [], 12 | "functions": { 13 | "layer-nodejs16x": { 14 | "environment": { 15 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 16 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 17 | "NEW_RELIC_DISTRIBUTED_TRACING_ENABLED": "true", 18 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 19 | "NEW_RELIC_NO_CONFIG_FILE": "true", 20 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 21 | }, 22 | "events": [ 23 | { 24 | "schedule": "rate(5 minutes)" 25 | } 26 | ], 27 | "handler": "newrelic-lambda-wrapper.handler", 28 | "layers": [ 29 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 30 | ], 31 | "package": { 32 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 33 | "include": ["handler.js"] 34 | }, 35 | "runtime": "nodejs16.x" 36 | }, 37 | "layer-nodejs18x": { 38 | "environment": { 39 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 40 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 41 | "NEW_RELIC_DISTRIBUTED_TRACING_ENABLED": "true", 42 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 43 | "NEW_RELIC_NO_CONFIG_FILE": "true", 44 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 45 | }, 46 | "events": [ 47 | { 48 | "schedule": "rate(5 minutes)" 49 | } 50 | ], 51 | "handler": "newrelic-lambda-wrapper.handler", 52 | "layers": [ 53 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 54 | ], 55 | "package": { 56 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 57 | "include": ["handler.js"] 58 | }, 59 | "runtime": "nodejs18.x" 60 | } 61 | }, 62 | "plugins": ["serverless-newrelic-lambda-layers"], 63 | "provider": { 64 | "name": "aws", 65 | "region": "us-east-1", 66 | "stackTags": { 67 | "environment": "us-testing", 68 | "owning_team": "LAMBDA", 69 | "product": "aws-lambda" 70 | }, 71 | "stage": "prod", 72 | "tags": { 73 | "environment": "us-testing", 74 | "owning_team": "LAMBDA", 75 | "product": "aws-lambda" 76 | } 77 | }, 78 | "service": "newrelic-lambda-layers-nodejs-example" 79 | } 80 | -------------------------------------------------------------------------------- /tests/fixtures/log-level.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "logLevel": "error", 25 | "logEnabled": true 26 | } 27 | }, 28 | "disabledDeprecations": [], 29 | "functions": { 30 | "layer-nodejs16x": { 31 | "events": [{ "schedule": "rate(5 minutes)" }], 32 | "handler": "newrelic-lambda-wrapper.handler", 33 | "layers": [ 34 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 35 | ], 36 | "package": { 37 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 38 | "include": ["handler.js"] 39 | }, 40 | "runtime": "nodejs16.x", 41 | "environment": { 42 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 43 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 44 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 45 | "NEW_RELIC_LOG": "stdout", 46 | "NEW_RELIC_LOG_ENABLED": "true", 47 | "NEW_RELIC_LOG_LEVEL": "error", 48 | "NEW_RELIC_NO_CONFIG_FILE": "true", 49 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 50 | } 51 | }, 52 | "layer-nodejs18x": { 53 | "events": [{ "schedule": "rate(5 minutes)" }], 54 | "handler": "newrelic-lambda-wrapper.handler", 55 | "layers": [ 56 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 57 | ], 58 | "package": { 59 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 60 | "include": ["handler.js"] 61 | }, 62 | "runtime": "nodejs18.x", 63 | "environment": { 64 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 65 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 66 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 67 | "NEW_RELIC_LOG": "stdout", 68 | "NEW_RELIC_LOG_ENABLED": "true", 69 | "NEW_RELIC_LOG_LEVEL": "error", 70 | "NEW_RELIC_NO_CONFIG_FILE": "true", 71 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/fixtures/arm64.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "logLevel": "debug" 8 | } 9 | }, 10 | "disabledDeprecations": [], 11 | "functions": { 12 | "layer-nodejs16x": { 13 | "environment": { 14 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 15 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 16 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 17 | "NEW_RELIC_NO_CONFIG_FILE": "true", 18 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 19 | }, 20 | "events": [ 21 | { 22 | "schedule": "rate(5 minutes)" 23 | } 24 | ], 25 | "handler": "newrelic-lambda-wrapper.handler", 26 | "layers": [ 27 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16XARM64:105" 28 | ], 29 | "package": { 30 | "exclude": [ 31 | "./**", 32 | "!newrelic-wrapper-helper.js" 33 | ], 34 | "include": [ 35 | "handler.js" 36 | ] 37 | }, 38 | "runtime": "nodejs16.x" 39 | }, 40 | "layer-nodejs18x": { 41 | "environment": { 42 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 43 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 44 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 45 | "NEW_RELIC_NO_CONFIG_FILE": "true", 46 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 47 | }, 48 | "events": [ 49 | { 50 | "schedule": "rate(5 minutes)" 51 | } 52 | ], 53 | "handler": "newrelic-lambda-wrapper.handler", 54 | "layers": [ 55 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18XARM64:127" 56 | ], 57 | "package": { 58 | "exclude": [ 59 | "./**", 60 | "!newrelic-wrapper-helper.js" 61 | ], 62 | "include": [ 63 | "handler.js" 64 | ] 65 | }, 66 | "runtime": "nodejs18.x" 67 | } 68 | }, 69 | "plugins": [ 70 | "serverless-newrelic-lambda-layers" 71 | ], 72 | "provider": { 73 | "architecture": "arm64", 74 | "name": "aws", 75 | "region": "us-east-1", 76 | "stackTags": { 77 | "environment": "us-testing", 78 | "owning_team": "LAMBDA", 79 | "product": "aws-lambda" 80 | }, 81 | "stage": "prod", 82 | "tags": { 83 | "environment": "us-testing", 84 | "owning_team": "LAMBDA", 85 | "product": "aws-lambda" 86 | } 87 | }, 88 | "service": "newrelic-lambda-layers-nodejs-example" 89 | } 90 | -------------------------------------------------------------------------------- /tests/fixtures/license-key-secret-disabled.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "disableLicenseKeySecret": false, 8 | "logLevel": "debug" 9 | } 10 | }, 11 | "disabledDeprecations": [], 12 | "functions": { 13 | "layer-nodejs16x": { 14 | "environment": { 15 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 16 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 17 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 18 | "NEW_RELIC_NO_CONFIG_FILE": "true", 19 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 20 | }, 21 | "events": [ 22 | { 23 | "schedule": "rate(5 minutes)" 24 | } 25 | ], 26 | "handler": "newrelic-lambda-wrapper.handler", 27 | "layers": [ 28 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 29 | ], 30 | "package": { 31 | "exclude": [ 32 | "./**", 33 | "!newrelic-wrapper-helper.js" 34 | ], 35 | "include": [ 36 | "handler.js" 37 | ] 38 | }, 39 | "runtime": "nodejs16.x" 40 | }, 41 | "layer-nodejs18x": { 42 | "environment": { 43 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 44 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 45 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 46 | "NEW_RELIC_NO_CONFIG_FILE": "true", 47 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 48 | }, 49 | "events": [ 50 | { 51 | "schedule": "rate(5 minutes)" 52 | } 53 | ], 54 | "handler": "newrelic-lambda-wrapper.handler", 55 | "layers": [ 56 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 57 | ], 58 | "package": { 59 | "exclude": [ 60 | "./**", 61 | "!newrelic-wrapper-helper.js" 62 | ], 63 | "include": [ 64 | "handler.js" 65 | ] 66 | }, 67 | "runtime": "nodejs18.x" 68 | } 69 | }, 70 | "plugins": ["serverless-newrelic-lambda-layers"], 71 | "provider": { 72 | "name": "aws", 73 | "region": "us-east-1", 74 | "stackTags": { 75 | "environment": "us-testing", 76 | "owning_team": "LAMBDA", 77 | "product": "aws-lambda" 78 | }, 79 | "stage": "prod", 80 | "tags": { 81 | "environment": "us-testing", 82 | "owning_team": "LAMBDA", 83 | "product": "aws-lambda" 84 | } 85 | }, 86 | "service": "newrelic-lambda-layers-nodejs-example" 87 | } 88 | -------------------------------------------------------------------------------- /tests/fixtures/debug-log-level.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 24 | "logLevel": "error", 25 | "debug": true, 26 | "logEnabled": true 27 | } 28 | }, 29 | "disabledDeprecations": [], 30 | "functions": { 31 | "layer-nodejs16x": { 32 | "events": [{ "schedule": "rate(5 minutes)" }], 33 | "handler": "newrelic-lambda-wrapper.handler", 34 | "layers": [ 35 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 36 | ], 37 | "package": { 38 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 39 | "include": ["handler.js"] 40 | }, 41 | "runtime": "nodejs16.x", 42 | "environment": { 43 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 44 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 45 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 46 | "NEW_RELIC_LOG": "stdout", 47 | "NEW_RELIC_LOG_ENABLED": "true", 48 | "NEW_RELIC_LOG_LEVEL": "error", 49 | "NEW_RELIC_NO_CONFIG_FILE": "true", 50 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 51 | } 52 | }, 53 | "layer-nodejs18x": { 54 | "events": [{ "schedule": "rate(5 minutes)" }], 55 | "handler": "newrelic-lambda-wrapper.handler", 56 | "layers": [ 57 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 58 | ], 59 | "package": { 60 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 61 | "include": ["handler.js"] 62 | }, 63 | "runtime": "nodejs18.x", 64 | "environment": { 65 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 66 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 67 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 68 | "NEW_RELIC_LOG": "stdout", 69 | "NEW_RELIC_LOG_ENABLED": "true", 70 | "NEW_RELIC_LOG_LEVEL": "error", 71 | "NEW_RELIC_NO_CONFIG_FILE": "true", 72 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/fixtures/provider-environment.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | }, 17 | "environment": { 18 | "NEW_RELIC_LOG_LEVEL": "error" 19 | } 20 | }, 21 | "plugins": ["serverless-newrelic-lambda-layers"], 22 | "configValidationMode": "warn", 23 | "custom": { 24 | "newRelic": { 25 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 26 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 27 | "logEnabled": true 28 | } 29 | }, 30 | "disabledDeprecations": [], 31 | "functions": { 32 | "layer-nodejs16x": { 33 | "events": [{ "schedule": "rate(5 minutes)" }], 34 | "handler": "newrelic-lambda-wrapper.handler", 35 | "layers": [ 36 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 37 | ], 38 | "package": { 39 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 40 | "include": ["handler.js"] 41 | }, 42 | "runtime": "nodejs16.x", 43 | "environment": { 44 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 45 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 46 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 47 | "NEW_RELIC_LOG": "stdout", 48 | "NEW_RELIC_LOG_ENABLED": "true", 49 | "NEW_RELIC_LOG_LEVEL": "error", 50 | "NEW_RELIC_NO_CONFIG_FILE": "true", 51 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 52 | } 53 | }, 54 | "layer-nodejs18x": { 55 | "events": [{ "schedule": "rate(5 minutes)" }], 56 | "handler": "newrelic-lambda-wrapper.handler", 57 | "layers": [ 58 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 59 | ], 60 | "package": { 61 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 62 | "include": ["handler.js"] 63 | }, 64 | "runtime": "nodejs18.x", 65 | "environment": { 66 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 67 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 68 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 69 | "NEW_RELIC_LOG": "stdout", 70 | "NEW_RELIC_LOG_ENABLED": "true", 71 | "NEW_RELIC_LOG_LEVEL": "error", 72 | "NEW_RELIC_NO_CONFIG_FILE": "true", 73 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /examples/dotnet/readme.md: -------------------------------------------------------------------------------- 1 | # Serverless NewRelic Dotnet Example 2 | 3 | ## Overview 4 | This document serves as a guide for building, deploying, and running a simple Dotnet application through the NewRelic Serverless plugin. The example demonstrates an easy-to-follow workflow to deploy and instrument the application using the NewRelic Serverless plugin. 5 | 6 | ## Requirement 7 | To work with this Serverless NewRelic Dotnet example project, ensure your environment meets the following requirements: 8 | - **Dotnet SDK**: Version 6.0 or above 9 | - **Command-Line Interface (CLI)**: Ability to run commands in Terminal or Command Prompt 10 | - **AWS Account**: Required for deployment using Serverless framework 11 | - **Serverless Framework**: Installed globally via npm 12 | 13 | ## Dependencies Install 14 | To install the necessary dependencies, follow these steps: 15 | 16 | 1. **Node.js and npm Setup**: 17 | - Ensure Node.js and npm are installed from the [official Node.js website](https://nodejs.org/). 18 | 19 | 2. **Install Serverless and NewRelic Plugin**: 20 | - Navigate to the example directory `cd examples/dotnet` where `package.json` is located. 21 | - Run: `npm install` 22 | This installs local dependencies, including the NewRelic serverless plugin. 23 | 24 | ## Build Dotnet Project 25 | To build the Dotnet project, execute the following steps: 26 | 27 | 1. **Run the `build.sh` File**: 28 | - Make sure the Dotnet tools path is exported globally in your environment. 29 | - Run: `./build.sh` 30 | This script will create a `newrelic-serverless-dotnet-example.zip` file, ready for deployment. 31 | 32 | 2. **Update NewRelic Configuration**: 33 | - Open the `serverless.yml` file. 34 | - Update the NewRelic configuration with your account details: 35 | ```yaml 36 | newRelic: 37 | accountId: your-nr-accountid 38 | apiKey: nr-api-key 39 | ``` 40 | 41 | ## Deploy 42 | Deploy the Dotnet function using Serverless framework and NewRelic instrumentation: 43 | 44 | 1. **Deploy Using Serverless CLI**: 45 | - In the terminal, ensure you are in the project's root directory. 46 | - Run: `sls deploy` 47 | This command deploys the Dotnet function to AWS Lambda and sets up instrumentation with NewRelic. 48 | 49 | 2. **Verify Deployment**: 50 | - Upon successful deployment, observe your AWS console for the created Lambda function. 51 | - Check NewRelic dashboard for instrumentation data related to the deployed function. 52 | 53 | For more information and troubleshooting, consult: 54 | - [Serverless Framework Documentation](https://www.serverless.com/framework/docs/) 55 | - [Newrelic Serverless Plugin Documentation](https://github.com/newrelic/serverless-newrelic-lambda-layers) 56 | - [Newrelic Documentation](https://docs.newrelic.com/) 57 | -------------------------------------------------------------------------------- /tests/fixtures/provider-environment-log-level.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | }, 17 | "environment": { 18 | "NEW_RELIC_LOG_LEVEL": "error" 19 | } 20 | }, 21 | "plugins": ["serverless-newrelic-lambda-layers"], 22 | "configValidationMode": "warn", 23 | "custom": { 24 | "newRelic": { 25 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 26 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 27 | "logLevel": "trace", 28 | "logEnabled": true 29 | } 30 | }, 31 | "disabledDeprecations": [], 32 | "functions": { 33 | "layer-nodejs16x": { 34 | "events": [{ "schedule": "rate(5 minutes)" }], 35 | "handler": "newrelic-lambda-wrapper.handler", 36 | "layers": [ 37 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 38 | ], 39 | "package": { 40 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 41 | "include": ["handler.js"] 42 | }, 43 | "runtime": "nodejs16.x", 44 | "environment": { 45 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 46 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 47 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 48 | "NEW_RELIC_LOG": "stdout", 49 | "NEW_RELIC_LOG_ENABLED": "true", 50 | "NEW_RELIC_LOG_LEVEL": "error", 51 | "NEW_RELIC_NO_CONFIG_FILE": "true", 52 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 53 | } 54 | }, 55 | "layer-nodejs18x": { 56 | "events": [{ "schedule": "rate(5 minutes)" }], 57 | "handler": "newrelic-lambda-wrapper.handler", 58 | "layers": [ 59 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 60 | ], 61 | "package": { 62 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 63 | "include": ["handler.js"] 64 | }, 65 | "runtime": "nodejs18.x", 66 | "environment": { 67 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 68 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 69 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 70 | "NEW_RELIC_LOG": "stdout", 71 | "NEW_RELIC_LOG_ENABLED": "true", 72 | "NEW_RELIC_LOG_LEVEL": "error", 73 | "NEW_RELIC_NO_CONFIG_FILE": "true", 74 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/fixtures/eu.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "debug": true, 8 | "logEnabled": true, 9 | "nrRegion": "eu" 10 | } 11 | }, 12 | "disabledDeprecations": [], 13 | "functions": { 14 | "layer-nodejs16x": { 15 | "environment": { 16 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 17 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 18 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 19 | "NEW_RELIC_LOG": "stdout", 20 | "NEW_RELIC_LOG_ENABLED": "true", 21 | "NEW_RELIC_LOG_LEVEL": "debug", 22 | "NEW_RELIC_NO_CONFIG_FILE": "true", 23 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 24 | }, 25 | "events": [ 26 | { 27 | "schedule": "rate(5 minutes)" 28 | } 29 | ], 30 | "handler": "newrelic-lambda-wrapper.handler", 31 | "layers": [ 32 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 33 | ], 34 | "package": { 35 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 36 | "include": ["handler.js"] 37 | }, 38 | "runtime": "nodejs16.x" 39 | }, 40 | "layer-nodejs18x": { 41 | "environment": { 42 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 43 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 44 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 45 | "NEW_RELIC_LOG": "stdout", 46 | "NEW_RELIC_LOG_ENABLED": "true", 47 | "NEW_RELIC_LOG_LEVEL": "debug", 48 | "NEW_RELIC_NO_CONFIG_FILE": "true", 49 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 50 | }, 51 | "events": [ 52 | { 53 | "schedule": "rate(5 minutes)" 54 | } 55 | ], 56 | "handler": "newrelic-lambda-wrapper.handler", 57 | "layers": [ 58 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 59 | ], 60 | "package": { 61 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 62 | "include": ["handler.js"] 63 | }, 64 | "runtime": "nodejs18.x" 65 | } 66 | }, 67 | "plugins": ["serverless-newrelic-lambda-layers"], 68 | "provider": { 69 | "name": "aws", 70 | "region": "us-east-1", 71 | "stackTags": { 72 | "environment": "us-testing", 73 | "owning_team": "LAMBDA", 74 | "product": "aws-lambda" 75 | }, 76 | "stage": "prod", 77 | "tags": { 78 | "environment": "us-testing", 79 | "owning_team": "LAMBDA", 80 | "product": "aws-lambda" 81 | } 82 | }, 83 | "service": "newrelic-lambda-layers-nodejs-example" 84 | } 85 | -------------------------------------------------------------------------------- /src/api.ts: -------------------------------------------------------------------------------- 1 | import { HttpsProxyAgent } from "https-proxy-agent"; 2 | import fetch from "node-fetch"; 3 | 4 | export const nerdgraphFetch = async ( 5 | apiKey: string, 6 | region: string, 7 | query: string, 8 | proxy?: string, 9 | context?: any 10 | ) => { 11 | const gqlUrl = 12 | region === "eu" 13 | ? "https://api.eu.newrelic.com/graphql" 14 | : region === "staging" 15 | ? "https://staging-api.newrelic.com/graphql" 16 | : "https://api.newrelic.com/graphql"; 17 | 18 | const agent = 19 | typeof proxy === "undefined" ? null : new HttpsProxyAgent(proxy); 20 | 21 | const res = await fetch(gqlUrl, { 22 | agent, 23 | body: JSON.stringify({ query }), 24 | headers: { 25 | "API-Key": apiKey, 26 | "Content-Type": "application/json", 27 | }, 28 | method: "POST", 29 | }).catch((e) => { 30 | context.log.error(`Error fetching from NerdGraph; ${context.caller}`); 31 | context.log.error(e); 32 | return null; 33 | }); 34 | return res.json(); 35 | }; 36 | 37 | export const cloudLinkAccountMutation = ( 38 | accountId: number, 39 | roleArn: string, 40 | linkedAccount: string 41 | ) => ` 42 | mutation { 43 | cloudLinkAccount(accountId: ${accountId}, accounts: {aws: [{arn: "${roleArn}", name: "${linkedAccount}"}]}) { 44 | linkedAccounts { 45 | id 46 | name 47 | } 48 | errors { 49 | message 50 | } 51 | } 52 | } 53 | `; 54 | 55 | export const cloudServiceIntegrationMutation = ( 56 | accountId: number, 57 | provider: string, 58 | service: string, 59 | linkedAccountId: number 60 | ) => ` 61 | mutation { 62 | cloudConfigureIntegration ( 63 | accountId: ${accountId}, 64 | integrations: {${provider}: {${service}: {linkedAccountId: ${linkedAccountId}}}} 65 | ) { 66 | integrations { 67 | id 68 | name 69 | service { 70 | id 71 | name 72 | } 73 | } 74 | errors { 75 | linkedAccountId 76 | message 77 | } 78 | } 79 | } 80 | `; 81 | 82 | export const fetchLinkedAccounts = (accountId: number) => ` 83 | query { 84 | actor { 85 | account(id: ${accountId}) { 86 | cloud { 87 | linkedAccounts { 88 | id 89 | name 90 | createdAt 91 | updatedAt 92 | authLabel 93 | externalId 94 | nrAccountId 95 | } 96 | } 97 | } 98 | } 99 | } 100 | `; 101 | 102 | export const fetchLicenseKey = (accountId: number) => ` 103 | { 104 | actor { 105 | account(id: ${accountId}) { 106 | licenseKey 107 | name 108 | id 109 | } 110 | } 111 | } 112 | `; 113 | -------------------------------------------------------------------------------- /tests/fixtures/log-ingestion-via-extension.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "configValidationMode": "warn", 3 | "custom": { 4 | "newRelic": { 5 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 6 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}", 7 | "disableAutoSubscription": true, 8 | "enableFunctionLogs": true, 9 | "enableIntegration": true, 10 | "logLevel": "debug" 11 | } 12 | }, 13 | "disabledDeprecations": [], 14 | "functions": { 15 | "layer-nodejs16x": { 16 | "environment": { 17 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 18 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 19 | "NEW_RELIC_EXTENSION_SEND_FUNCTION_LOGS": "true", 20 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 21 | "NEW_RELIC_NO_CONFIG_FILE": "true", 22 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 23 | }, 24 | "events": [ 25 | { 26 | "schedule": "rate(5 minutes)" 27 | } 28 | ], 29 | "handler": "newrelic-lambda-wrapper.handler", 30 | "layers": [ 31 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 32 | ], 33 | "package": { 34 | "exclude": [ 35 | "./**", 36 | "!newrelic-wrapper-helper.js" 37 | ], 38 | "include": [ 39 | "handler.js" 40 | ] 41 | }, 42 | "runtime": "nodejs16.x" 43 | }, 44 | "layer-nodejs18x": { 45 | "environment": { 46 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 47 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 48 | "NEW_RELIC_EXTENSION_SEND_FUNCTION_LOGS": "true", 49 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 50 | "NEW_RELIC_NO_CONFIG_FILE": "true", 51 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 52 | }, 53 | "events": [ 54 | { 55 | "schedule": "rate(5 minutes)" 56 | } 57 | ], 58 | "handler": "newrelic-lambda-wrapper.handler", 59 | "layers": [ 60 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 61 | ], 62 | "package": { 63 | "exclude": [ 64 | "./**", 65 | "!newrelic-wrapper-helper.js" 66 | ], 67 | "include": [ 68 | "handler.js" 69 | ] 70 | }, 71 | "runtime": "nodejs18.x" 72 | } 73 | }, 74 | "plugins": ["serverless-newrelic-lambda-layers"], 75 | "provider": { 76 | "name": "aws", 77 | "region": "us-east-1", 78 | "stackTags": { 79 | "environment": "us-testing", 80 | "owning_team": "LAMBDA", 81 | "product": "aws-lambda" 82 | }, 83 | "stage": "prod", 84 | "tags": { 85 | "environment": "us-testing", 86 | "owning_team": "LAMBDA", 87 | "product": "aws-lambda" 88 | } 89 | }, 90 | "service": "newrelic-lambda-layers-nodejs-example" 91 | } 92 | -------------------------------------------------------------------------------- /templates/nr-lambda-integration-role.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Parameters: 3 | NewRelicAccountNumber: 4 | Type: String 5 | Description: The Newrelic account number to send data 6 | AllowedPattern: '[0-9]+' 7 | PolicyName: 8 | Type: String 9 | Description: 'Policy name of the policy to use in the Role. If no value is supplied it will use the AWS default ReadOnlyAccess. 10 | The default AWS ReadOnlyAccess policy is managed by AWS and automatically gains new permissions as new services are introduced but 11 | includes a broad set of permissions which are not required by NewRelic integrations. 12 | If a value is supplied a custom policy will be created with the provided name. This custom policy only includes the minimum 13 | required permissions to allow NewRelic to monitor your Lambda functions. Take into account that this policy is not automatically 14 | updated by AWS, and must be managed by you.' 15 | 16 | 17 | Conditions: 18 | UseCustomPolicy: !Not [!Equals [ !Ref PolicyName, '']] 19 | UseDefaultPolicy: !Equals [ !Ref PolicyName, ''] 20 | 21 | Resources: 22 | NewRelicDefaultPolicyLambdaRole: 23 | Type: 'AWS::IAM::Role' 24 | Condition: UseDefaultPolicy 25 | Properties: 26 | ManagedPolicyArns: 27 | - arn:aws:iam::aws:policy/ReadOnlyAccess 28 | RoleName: !Join ['_', ['NewRelicLambdaIntegrationRole', !Ref NewRelicAccountNumber]] 29 | AssumeRolePolicyDocument: 30 | Version: 2012-10-17 31 | Statement: 32 | - Effect: Allow 33 | Principal: 34 | AWS: !Sub 'arn:aws:iam::754728514883:root' 35 | Action: 'sts:AssumeRole' 36 | Condition: 37 | StringEquals: 38 | 'sts:ExternalId': !Ref NewRelicAccountNumber 39 | 40 | NewRelicCustomPolicyLambdaRole: 41 | Type: 'AWS::IAM::Role' 42 | Condition: UseCustomPolicy 43 | Properties: 44 | RoleName: !Join ['_', ['NewRelicLambdaIntegrationRole', !Ref NewRelicAccountNumber]] 45 | AssumeRolePolicyDocument: 46 | Version: 2012-10-17 47 | Statement: 48 | - Effect: Allow 49 | Principal: 50 | AWS: !Sub 'arn:aws:iam::754728514883:root' 51 | Action: 'sts:AssumeRole' 52 | Condition: 53 | StringEquals: 54 | 'sts:ExternalId': !Ref NewRelicAccountNumber 55 | 56 | NewRelicLambdaCustomPolicy: 57 | Type: 'AWS::IAM::ManagedPolicy' 58 | Condition: UseCustomPolicy 59 | Properties: 60 | ManagedPolicyName: !Ref PolicyName 61 | Roles: 62 | - !Ref NewRelicCustomPolicyLambdaRole 63 | PolicyDocument: 64 | Version: 2012-10-17 65 | Statement: 66 | - Effect: Allow 67 | Action: 68 | - 'cloudwatch:GetMetricStatistics' 69 | - 'cloudwatch:ListMetrics' 70 | - 'cloudwatch:GetMetricData' 71 | - 'lambda:GetAccountSettings' 72 | - 'lambda:ListFunctions' 73 | - 'lambda:ListAliases' 74 | - 'lambda:ListTags' 75 | - 'lambda:ListEventSourceMappings' 76 | Resource: '*' 77 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at opensource@newrelic.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /examples/java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.serverless 5 | java-example 6 | jar 7 | dev 8 | java-example 9 | 10 | 11 | 1.8 12 | 1.8 13 | UTF-8 14 | 15 | 16 | 17 | 18 | com.amazonaws 19 | aws-lambda-java-log4j2 20 | 1.6.0 21 | 22 | 23 | org.apache.logging.log4j 24 | log4j-core 25 | 2.24.3 26 | 27 | 28 | org.apache.logging.log4j 29 | log4j-api 30 | 2.24.3 31 | 32 | 33 | com.fasterxml.jackson.core 34 | jackson-core 35 | 2.18.3 36 | 37 | 38 | com.fasterxml.jackson.core 39 | jackson-databind 40 | 2.18.3 41 | 42 | 43 | com.fasterxml.jackson.core 44 | jackson-annotations 45 | 2.18.3 46 | 47 | 48 | 49 | 50 | 51 | 60 | 61 | org.apache.maven.plugins 62 | maven-shade-plugin 63 | 2.3 64 | 65 | false 66 | 67 | 68 | 69 | package 70 | 71 | shade 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | com.github.edwgiz 84 | maven-shade-plugin.log4j2-cachefile-transformer 85 | 2.8.1 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /tests/paginatedFunctionsList.json: -------------------------------------------------------------------------------- 1 | { 2 | "paginated": { 3 | "first": { 4 | "Functions": [ 5 | { 6 | "FunctionName": "FirstFunctionName", 7 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:FirstFunctionName" 8 | } 9 | ], 10 | "NextMarker": "second" 11 | }, 12 | "second": { 13 | "Functions": [ 14 | { 15 | "FunctionName": "SecondFunctionName", 16 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:SecondFunctionName" 17 | } 18 | ], 19 | "NextMarker": "third" 20 | }, 21 | "third": { 22 | "Functions": [ 23 | { 24 | "FunctionName": "ThirdFunctionName", 25 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:ThirdFunctionName" 26 | } 27 | ], 28 | "NextMarker": "fourth" 29 | }, 30 | "fourth": { 31 | "Functions": [ 32 | { 33 | "FunctionName": "newrelic-log-ingestion-0123456789ab", 34 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:newrelic-log-ingestion-0123456789ab" 35 | } 36 | ] 37 | } 38 | }, 39 | "paginatedNoMatch": { 40 | "first": { 41 | "Functions": [ 42 | { 43 | "FunctionName": "FirstFunctionName", 44 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:FirstFunctionName" 45 | } 46 | ], 47 | "NextMarker": "second" 48 | }, 49 | "second": { 50 | "Functions": [ 51 | { 52 | "FunctionName": "SecondFunctionName", 53 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:SecondFunctionName" 54 | } 55 | ], 56 | "NextMarker": "third" 57 | }, 58 | "third": { 59 | "Functions": [ 60 | { 61 | "FunctionName": "ThirdFunctionName", 62 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:ThirdFunctionName" 63 | } 64 | ], 65 | "NextMarker": "fourth" 66 | }, 67 | "fourth": { 68 | "Functions": [ 69 | { 70 | "FunctionName": "FourthFunctionName", 71 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:policy/FourthFunctionName" 72 | } 73 | ] 74 | } 75 | }, 76 | "nonPaginated": { 77 | "Functions": [ 78 | { 79 | "FunctionName": "FirstFunctionName", 80 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:FirstFunctionName" 81 | }, 82 | { 83 | "FunctionName": "SecondFunctionName", 84 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:SecondFunctionName" 85 | }, 86 | { 87 | "FunctionName": "ThirdFunctionName", 88 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:ThirdFunctionName" 89 | }, 90 | { 91 | "FunctionName": "newrelic-log-ingestion-0123456789ab", 92 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:newrelic-log-ingestion-0123456789ab" 93 | } 94 | ] 95 | }, 96 | "nonPaginatedNoMatch": { 97 | "Functions": [ 98 | { 99 | "FunctionName": "FirstFunctionName", 100 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:FirstFunctionName", 101 | "Path": "/service-role/" 102 | }, 103 | { 104 | "FunctionName": "SecondFunctionName", 105 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:SecondFunctionName", 106 | "Path": "/service-role/" 107 | }, 108 | { 109 | "FunctionName": "ThirdFunctionName", 110 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:function:ThirdFunctionName", 111 | "Path": "/service-role/" 112 | }, 113 | { 114 | "FunctionName": "FourthFunctionName", 115 | "FunctionArn": "arn:aws:lambda:us-east-1:123456789:policy/FourthFunctionName", 116 | "Path": "/" 117 | } 118 | ] 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /tests/fixtures/node-versions.output.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": "newrelic-lambda-layers-nodejs-example", 3 | "provider": { 4 | "name": "aws", 5 | "stage": "prod", 6 | "region": "us-east-1", 7 | "stackTags": { 8 | "environment": "us-testing", 9 | "owning_team": "LAMBDA", 10 | "product": "aws-lambda" 11 | }, 12 | "tags": { 13 | "environment": "us-testing", 14 | "owning_team": "LAMBDA", 15 | "product": "aws-lambda" 16 | } 17 | }, 18 | "plugins": ["serverless-newrelic-lambda-layers"], 19 | "configValidationMode": "warn", 20 | "custom": { 21 | "newRelic": { 22 | "accountId": "${env:NEW_RELIC_ACCOUNT_ID}", 23 | "apiKey": "${env:NEW_RELIC_PERSONAL_API_KEY}" 24 | } 25 | }, 26 | "disabledDeprecations": [], 27 | "functions": { 28 | "layer-nodejs16x": { 29 | "events": [{ "schedule": "rate(5 minutes)" }], 30 | "handler": "newrelic-lambda-wrapper.handler", 31 | "layers": [ 32 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS16X:105" 33 | ], 34 | "package": { 35 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 36 | "include": ["handler.js"] 37 | }, 38 | "runtime": "nodejs16.x", 39 | "environment": { 40 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 41 | "NEW_RELIC_APP_NAME": "layer-nodejs16x", 42 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 43 | "NEW_RELIC_NO_CONFIG_FILE": "true", 44 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 45 | } 46 | }, 47 | "layer-nodejs18x": { 48 | "events": [{ "schedule": "rate(5 minutes)" }], 49 | "handler": "newrelic-lambda-wrapper.handler", 50 | "layers": [ 51 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS18X:127" 52 | ], 53 | "package": { 54 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 55 | "include": ["handler.js"] 56 | }, 57 | "runtime": "nodejs18.x", 58 | "environment": { 59 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 60 | "NEW_RELIC_APP_NAME": "layer-nodejs18x", 61 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 62 | "NEW_RELIC_NO_CONFIG_FILE": "true", 63 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 64 | } 65 | }, 66 | "layer-nodejs20x": { 67 | "events": [{ "schedule": "rate(5 minutes)" }], 68 | "handler": "newrelic-lambda-wrapper.handler", 69 | "layers": [ 70 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS20X:99" 71 | ], 72 | "package": { 73 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 74 | "include": ["handler.js"] 75 | }, 76 | "runtime": "nodejs20.x", 77 | "environment": { 78 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 79 | "NEW_RELIC_APP_NAME": "layer-nodejs20x", 80 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 81 | "NEW_RELIC_NO_CONFIG_FILE": "true", 82 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 83 | } 84 | }, 85 | "layer-nodejs22x": { 86 | "events": [{ "schedule": "rate(5 minutes)" }], 87 | "handler": "newrelic-lambda-wrapper.handler", 88 | "layers": [ 89 | "arn:aws:lambda:us-east-1:451483290750:layer:NewRelicNodeJS22X:55" 90 | ], 91 | "package": { 92 | "exclude": ["./**", "!newrelic-wrapper-helper.js"], 93 | "include": ["handler.js"] 94 | }, 95 | "runtime": "nodejs22.x", 96 | "environment": { 97 | "NEW_RELIC_ACCOUNT_ID": "${env:NEW_RELIC_ACCOUNT_ID}", 98 | "NEW_RELIC_APP_NAME": "layer-nodejs22x", 99 | "NEW_RELIC_LAMBDA_HANDLER": "handler.handler", 100 | "NEW_RELIC_NO_CONFIG_FILE": "true", 101 | "NEW_RELIC_TRUSTED_ACCOUNT_KEY": "${env:NEW_RELIC_ACCOUNT_ID}" 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tests/paginatedPoliciesList.json: -------------------------------------------------------------------------------- 1 | { 2 | "paginated": { 3 | "first": { 4 | "Policies": [ 5 | { 6 | "PolicyName": "FirstPolicyName", 7 | "Arn": "arn:aws:iam::123456789:policy/service-role/FirstPolicyName", 8 | "Path": "/service-role/" 9 | } 10 | ], 11 | "IsTruncated": true, 12 | "Marker": "second" 13 | }, 14 | "second": { 15 | "Policies": [ 16 | { 17 | "PolicyName": "SecondPolicyName", 18 | "Arn": "arn:aws:iam::123456789:policy/service-role/SecondPolicyName", 19 | "Path": "/service-role/" 20 | } 21 | ], 22 | "IsTruncated": true, 23 | "Marker": "third" 24 | }, 25 | "third": { 26 | "Policies": [ 27 | { 28 | "PolicyName": "ThirdPolicyName", 29 | "Arn": "arn:aws:iam::123456789:policy/service-role/ThirdPolicyName", 30 | "Path": "/service-role/" 31 | } 32 | ], 33 | "IsTruncated": true, 34 | "Marker": "fourth" 35 | }, 36 | "fourth": { 37 | "Policies": [ 38 | { 39 | "PolicyName": "NewRelic-ViewLicenseKey-us-east-1", 40 | "Arn": "arn:aws:iam::123456789:policy/NewRelic-ViewLicenseKey-us-east-1", 41 | "Path": "/" 42 | } 43 | ], 44 | "IsTruncated": false, 45 | "Marker": "end" 46 | } 47 | }, 48 | "paginatedNoMatch": { 49 | "first": { 50 | "Policies": [ 51 | { 52 | "PolicyName": "FirstPolicyName", 53 | "Arn": "arn:aws:iam::123456789:policy/service-role/FirstPolicyName", 54 | "Path": "/service-role/" 55 | } 56 | ], 57 | "IsTruncated": true, 58 | "Marker": "second" 59 | }, 60 | "second": { 61 | "Policies": [ 62 | { 63 | "PolicyName": "SecondPolicyName", 64 | "Arn": "arn:aws:iam::123456789:policy/service-role/SecondPolicyName", 65 | "Path": "/service-role/" 66 | } 67 | ], 68 | "IsTruncated": true, 69 | "Marker": "third" 70 | }, 71 | "third": { 72 | "Policies": [ 73 | { 74 | "PolicyName": "ThirdPolicyName", 75 | "Arn": "arn:aws:iam::123456789:policy/service-role/ThirdPolicyName", 76 | "Path": "/service-role/" 77 | } 78 | ], 79 | "IsTruncated": true, 80 | "Marker": "fourth" 81 | }, 82 | "fourth": { 83 | "Policies": [ 84 | { 85 | "PolicyName": "FourthPolicyName", 86 | "Arn": "arn:aws:iam::123456789:policy/FourthPolicyName", 87 | "Path": "/" 88 | } 89 | ], 90 | "IsTruncated": false, 91 | "Marker": "end" 92 | } 93 | }, 94 | "nonPaginated": { 95 | "Policies": [ 96 | { 97 | "PolicyName": "FirstPolicyName", 98 | "Arn": "arn:aws:iam::123456789:policy/service-role/FirstPolicyName", 99 | "Path": "/service-role/" 100 | }, 101 | { 102 | "PolicyName": "SecondPolicyName", 103 | "Arn": "arn:aws:iam::123456789:policy/service-role/SecondPolicyName", 104 | "Path": "/service-role/" 105 | }, 106 | { 107 | "PolicyName": "ThirdPolicyName", 108 | "Arn": "arn:aws:iam::123456789:policy/service-role/ThirdPolicyName", 109 | "Path": "/service-role/" 110 | }, 111 | { 112 | "PolicyName": "NewRelic-ViewLicenseKey-us-east-1", 113 | "Arn": "arn:aws:iam::123456789:policy/NewRelic-ViewLicenseKey-us-east-1", 114 | "Path": "/" 115 | } 116 | ], 117 | "IsTruncated": false, 118 | "Marker": "end" 119 | }, 120 | "nonPaginatedNoMatch": { 121 | "Policies": [ 122 | { 123 | "PolicyName": "FirstPolicyName", 124 | "Arn": "arn:aws:iam::123456789:policy/service-role/FirstPolicyName", 125 | "Path": "/service-role/" 126 | }, 127 | { 128 | "PolicyName": "SecondPolicyName", 129 | "Arn": "arn:aws:iam::123456789:policy/service-role/SecondPolicyName", 130 | "Path": "/service-role/" 131 | }, 132 | { 133 | "PolicyName": "ThirdPolicyName", 134 | "Arn": "arn:aws:iam::123456789:policy/service-role/ThirdPolicyName", 135 | "Path": "/service-role/" 136 | }, 137 | { 138 | "PolicyName": "FourthPolicyName", 139 | "Arn": "arn:aws:iam::123456789:policy/FourthPolicyName", 140 | "Path": "/" 141 | } 142 | ], 143 | "IsTruncated": false, 144 | "Marker": "end" 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Creating Lambda Functions with New Relic Serverless-plugin 2 | 3 | This is a guide to creating lambdas instrumented with New Relic using Serverless-plugin 4 | 5 | ## Supported Runtimes 6 | 7 | | Runtime | Versions | 8 | |-------------|------------------------| 9 | | Python | `python3.8`, `python3.9`, `python3.10`, `python3.11`, `python3.12`, `python3.13` | 10 | | Node.js | `nodejs16.x`, `nodejs18.x`, `nodejs20.x`, `nodejs22.x` | 11 | | .NET | `dotnet3.1`, `dotnet6`, `dotnet8` | 12 | | Java | `java8.al2`, `java11`, `java17`, `java21` | 13 | | Provided | `provided.al2`, `provided.al2023` | 14 | | Ruby | `ruby3.2`, `ruby3.3`, `ruby3.4` | 15 | 16 | ## Quick Start 17 | 18 | ### Prerequisites 19 | 20 | Before you begin, ensure you have: 21 | 22 | 1. **Node.js** >= 16.x installed 23 | 2. **Serverless Framework** v3.x or v4.x 24 | ```bash 25 | npm install -g serverless 26 | ``` 27 | 3. **AWS CLI** configured with valid credentials 28 | ```bash 29 | aws configure 30 | ``` 31 | 4. **New Relic Account** ([Sign up](https://newrelic.com/signup)) 32 | - [Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id) 33 | - [Personal API Key](https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys#personal-api-key) 34 | 35 | ### Environment Setup 36 | 37 | Set your New Relic credentials as environment variables: 38 | 39 | ```bash 40 | export NEW_RELIC_ACCOUNT_ID=your-account-id-here 41 | export NEW_RELIC_PERSONAL_API_KEY=your-api-key-here 42 | ``` 43 | 44 | ### Deploy an Example 45 | 46 | ```bash 47 | # Choose your runtime example 48 | cd nodejs # or python, ruby, java, dotnet, etc. 49 | 50 | # Install dependencies 51 | npm install 52 | 53 | # Deploy to AWS 54 | sls deploy 55 | ``` 56 | 57 | That's it! Your Lambda function is now instrumented with New Relic monitoring. 58 | 59 | ## Creating Your Own Lambda Function 60 | 61 | ### Step 1: Create Project Structure 62 | 63 | ```bash 64 | mkdir my-lambda-function 65 | cd my-lambda-function 66 | ``` 67 | 68 | ### Step 2: Create Handler File 69 | 70 | Choose your runtime and create a handler: 71 | 72 | #### Node.js (`handler.js`) 73 | ```javascript 74 | module.exports.handler = async (event, context) => { 75 | console.log('Event:', JSON.stringify(event)); 76 | 77 | return { 78 | statusCode: 200, 79 | body: JSON.stringify({ message: 'Hello from Lambda!' }) 80 | }; 81 | }; 82 | ``` 83 | 84 | #### Python (`handler.py`) 85 | ```python 86 | import json 87 | 88 | def handler(event, context): 89 | print(f'Event: {json.dumps(event)}') 90 | 91 | return { 92 | 'statusCode': 200, 93 | 'body': json.dumps({'message': 'Hello from Lambda!'}) 94 | } 95 | ``` 96 | 97 | #### Ruby (`app.rb`) 98 | ```ruby 99 | require 'json' 100 | 101 | def lambda_handler(event:, context:) 102 | puts "Event: #{event.to_json}" 103 | 104 | { 105 | statusCode: 200, 106 | body: { 107 | message: "Hello from Lambda!" 108 | }.to_json 109 | } 110 | end 111 | ``` 112 | 113 | ### Step 3: Create `serverless.yml` 114 | 115 | ```yaml 116 | service: my-lambda-function 117 | 118 | provider: 119 | name: aws 120 | runtime: nodejs20.x # or python3.12, ruby3.3, java21, dotnet8, etc. 121 | region: us-east-1 122 | stage: prod 123 | 124 | plugins: 125 | - serverless-newrelic-lambda-layers 126 | 127 | custom: 128 | newRelic: 129 | accountId: ${env:NEW_RELIC_ACCOUNT_ID} 130 | apiKey: ${env:NEW_RELIC_PERSONAL_API_KEY} 131 | logLevel: info 132 | 133 | functions: 134 | myFunction: 135 | handler: handler.handler # format: filename.function_name 136 | events: 137 | - http: 138 | path: hello 139 | method: get 140 | ``` 141 | 142 | ### Step 4: Create `package.json` 143 | 144 | ```json 145 | { 146 | "name": "my-lambda-function", 147 | "version": "1.0.0", 148 | "scripts": { 149 | "deploy": "sls deploy", 150 | "remove": "sls remove", 151 | "logs": "sls logs -f myFunction -t" 152 | }, 153 | "devDependencies": { 154 | "serverless": "^4.12.0" 155 | }, 156 | "dependencies": { 157 | "serverless-newrelic-lambda-layers": "^5.12.0" 158 | } 159 | } 160 | ``` 161 | 162 | ### Step 5: Install & Deploy 163 | 164 | ```bash 165 | npm install 166 | sls deploy 167 | ``` 168 | 169 | ### Step 7: View in New Relic 170 | 171 | 1. Go to [New Relic One](https://one.newrelic.com) 172 | 2. Navigate to **Lambda Functions** in the left menu 173 | 3. Find your function and view metrics, traces, and logs 174 | 175 | ## Runtime-Specific Guides 176 | 177 | ### Java 178 | 179 | **Example:** [`java/`](./java) 180 | 181 | **Prerequisites:** 182 | - Java JDK 11+ 183 | - Maven 3.6+ 184 | 185 | **Structure:** 186 | ``` 187 | java/ 188 | ├── pom.xml 189 | ├── serverless.yml 190 | └── src/main/java/ 191 | └── Handler.java 192 | ``` 193 | 194 | **Build & Deploy:** 195 | ```bash 196 | mvn clean package 197 | sls deploy 198 | ``` 199 | 200 | **Supported Runtimes:** `java8.al2`, `java11`, `java17`, `java21` 201 | 202 | ### .NET 203 | 204 | **Example:** [`dotnet/`](./dotnet) 205 | 206 | **Prerequisites:** 207 | - .NET SDK 6.0+ 208 | 209 | **Build & Deploy:** 210 | ```bash 211 | chmod +x build.sh 212 | ./build.sh 213 | sls deploy 214 | ``` 215 | 216 | **Supported Runtimes:** `dotnet6`, `dotnet8` 217 | 218 | See [`dotnet/readme.md`](./dotnet/readme.md) for detailed instructions. 219 | 220 | 221 | -------------------------------------------------------------------------------- /tests/integration.test.ts: -------------------------------------------------------------------------------- 1 | const { getInstalledPathSync } = require("get-installed-path"); 2 | const log = require("@serverless/utils/log"); 3 | 4 | const serverlessPath = getInstalledPathSync("serverless", { local: true }); 5 | const AwsProvider = require(`${serverlessPath}/lib/plugins/aws/provider`); 6 | const Serverless = require(`${serverlessPath}/lib/serverless`); 7 | const Integration = require("../src/integration").default; 8 | 9 | const logShim = { 10 | error: console.error, // tslint:disable-line 11 | warning: console.log, // tslint:disable-line 12 | notice: console.log, // tslint:disable-line 13 | }; 14 | 15 | // for simulating AWS ListPolicies, just one per page in this test 16 | const policiesFixture = require("./paginatedPoliciesList.json"); 17 | const functionsFixture = require("./paginatedFunctionsList.json"); 18 | 19 | const setRequestEnv = (service, method) => { 20 | let fixture = policiesFixture 21 | if (service === 'Lambda' || method === 'listFunctions') { 22 | fixture = functionsFixture 23 | } 24 | return { fixture } 25 | } 26 | 27 | const returnPaginatedAwsRequest = (service, method, params) => { 28 | const { fixture } = setRequestEnv(service, method) 29 | if (!params.Marker) { 30 | return fixture.paginated.first; 31 | } 32 | return fixture.paginated[params.Marker]; 33 | }; 34 | const returnPaginatedNoMatchAwsRequest = (service, method, params) => { 35 | const { fixture } = setRequestEnv(service, method) 36 | if (!params.Marker) { 37 | return fixture.paginatedNoMatch.first; 38 | } 39 | return fixture.paginatedNoMatch[params.Marker]; 40 | }; 41 | const returnNonPaginatedAwsRequest = (service, method) => { 42 | const { fixture } = setRequestEnv(service, method) 43 | return fixture.nonPaginated; 44 | }; 45 | const returnNonPaginatedNoMatchAwsRequest = (service, method) => { 46 | const { fixture } = setRequestEnv(service, method) 47 | return fixture.nonPaginatedNoMatch; 48 | }; 49 | 50 | describe("Integration functions", () => { 51 | const stage = "dev"; 52 | const commands = []; 53 | const config = { commands, options: { stage }, log }; 54 | 55 | const serverless = new Serverless(config); 56 | 57 | serverless.setProvider("aws", new AwsProvider(serverless, config)); 58 | const awsProvider = serverless.getProvider("aws"); 59 | 60 | const pluginMock = { 61 | config, 62 | awsProvider: {}, 63 | serverless, 64 | region: "us-east-1", 65 | licenseKey: "nr-license-key", 66 | log: logShim, 67 | }; 68 | 69 | describe("checkForManagedSecretPolicy makes a ListPolicies request", () => { 70 | it("correctly finds match in multiple pages of results", async () => { 71 | awsProvider.request = jest.fn(returnPaginatedAwsRequest); 72 | pluginMock.awsProvider = { ...awsProvider }; 73 | const slsIntegration = new Integration(pluginMock); 74 | const existingPolicy = await slsIntegration.checkForManagedSecretPolicy(); 75 | expect(existingPolicy).toBeDefined(); 76 | expect(existingPolicy).toHaveProperty([ 77 | "currentRegionPolicy", 78 | 0, 79 | "PolicyName", 80 | ]); 81 | expect(existingPolicy.currentRegionPolicy[0].PolicyName).toEqual( 82 | policiesFixture.paginated.fourth.Policies[0].PolicyName 83 | ); 84 | expect(existingPolicy.secretExists).toBeTruthy(); 85 | }); 86 | it("correctly finds match in non-paginated results", async () => { 87 | awsProvider.request = jest.fn(returnNonPaginatedAwsRequest); 88 | pluginMock.awsProvider = { ...awsProvider }; 89 | const slsIntegration = new Integration(pluginMock); 90 | const existingPolicy = await slsIntegration.checkForManagedSecretPolicy(); 91 | expect(existingPolicy).toBeDefined(); 92 | expect(existingPolicy).toHaveProperty([ 93 | "currentRegionPolicy", 94 | 0, 95 | "PolicyName", 96 | ]); 97 | expect(existingPolicy.currentRegionPolicy[0].PolicyName).toEqual( 98 | policiesFixture.paginated.fourth.Policies[0].PolicyName 99 | ); 100 | expect(existingPolicy.secretExists).toBeTruthy(); 101 | }); 102 | it("correctly handles paginated results with no match", async () => { 103 | awsProvider.request = jest.fn(returnPaginatedNoMatchAwsRequest); 104 | pluginMock.awsProvider = { ...awsProvider }; 105 | const slsIntegration = new Integration(pluginMock); 106 | const existingPolicy = await slsIntegration.checkForManagedSecretPolicy(); 107 | expect(existingPolicy).toBeDefined(); 108 | expect(existingPolicy).toHaveProperty("currentRegionPolicy"); 109 | expect(existingPolicy.currentRegionPolicy).toHaveLength(0); 110 | expect(existingPolicy.secretExists).toBeFalsy(); 111 | }); 112 | it("correctly handles non-paginated results with no match", async () => { 113 | awsProvider.request = jest.fn(returnNonPaginatedNoMatchAwsRequest); 114 | pluginMock.awsProvider = { ...awsProvider }; 115 | const slsIntegration = new Integration(pluginMock); 116 | const existingPolicy = await slsIntegration.checkForManagedSecretPolicy(); 117 | expect(existingPolicy).toBeDefined(); 118 | expect(existingPolicy).toHaveProperty("currentRegionPolicy"); 119 | expect(existingPolicy.currentRegionPolicy).toHaveLength(0); 120 | expect(existingPolicy.secretExists).toBeFalsy(); 121 | }); 122 | }); 123 | describe("search for existing log ingestion function", () => { 124 | it("correctly finds match in multiple pages of results", async () => { 125 | awsProvider.request = jest.fn(returnPaginatedAwsRequest); 126 | pluginMock.awsProvider = { ...awsProvider }; 127 | const slsIntegration = new Integration(pluginMock); 128 | const existingIngestScript = await slsIntegration.getDestinationArn('newrelic-log-ingestion'); 129 | expect(existingIngestScript).toBeDefined(); 130 | expect(existingIngestScript).toEqual( 131 | functionsFixture.paginated.fourth.Functions[0].FunctionArn 132 | ); 133 | }); 134 | it("correctly finds match in non-paginated results", async () => { 135 | awsProvider.request = jest.fn(returnNonPaginatedAwsRequest); 136 | pluginMock.awsProvider = { ...awsProvider }; 137 | const slsIntegration = new Integration(pluginMock); 138 | const existingIngestScript = await slsIntegration.getDestinationArn('newrelic-log-ingestion'); 139 | expect(existingIngestScript).toBeDefined(); 140 | expect(existingIngestScript).toEqual( 141 | functionsFixture.paginated.fourth.Functions[0].FunctionArn 142 | ); 143 | }); 144 | it("correctly handles paginated results with no match", async () => { 145 | awsProvider.request = jest.fn(returnPaginatedNoMatchAwsRequest); 146 | pluginMock.awsProvider = { ...awsProvider }; 147 | const slsIntegration = new Integration(pluginMock); 148 | const existingIngestScript = await slsIntegration.getDestinationArn('newrelic-log-ingestion'); 149 | expect(existingIngestScript).toBeFalsy(); 150 | }); 151 | it("correctly handles non-paginated results with no match", async () => { 152 | awsProvider.request = jest.fn(returnNonPaginatedNoMatchAwsRequest); 153 | pluginMock.awsProvider = { ...awsProvider }; 154 | const slsIntegration = new Integration(pluginMock); 155 | const existingIngestScript = await slsIntegration.getDestinationArn('newrelic-log-ingestion'); 156 | expect(existingIngestScript).toBeFalsy(); 157 | }); 158 | }); 159 | }); 160 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 New Relic, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | New Relic Open Source community plus project banner. 2 | 3 | # serverless-newrelic-lambda-layers 4 | 5 | A [Serverless](https://serverless.com) plugin to add [New Relic](https://www.newrelic.com) 6 | observability using [AWS Lambda Layers](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) without requiring a code change. 7 | 8 | ## Requirements 9 | 10 | - [serverless](https://github.com/serverless/serverless) v3.x & v4.x (This plugin has been tested to work with Serverless Framework v3 & v4) 11 | - [Node](https://nodejs.org/) >= 16.x (if using Serverless version 3) 12 | 13 | ## Features 14 | 15 | - Installs and configures the New Relic AWS Integration 16 | - Supports Node.js, Python, Java, Ruby, Dotnet runtimes 17 | - No code change required to enable New Relic 18 | - Bundles New Relic's agent in a single layer 19 | - Configures CloudWatch subscription filters automatically 20 | 21 | ## Install 22 | 23 | With NPM: 24 | 25 | ```bash 26 | npm install --save-dev serverless-newrelic-lambda-layers 27 | ``` 28 | (Note: this plugin's production dependencies are now defined as peer dependencies. NPM v7 and later will install missing peer dependencies automatically, but v6 does not.) 29 | 30 | With yarn: 31 | 32 | ```bash 33 | yarn add --dev serverless-newrelic-lambda-layers 34 | ``` 35 | 36 | Add the plugin to your `serverless.yml`: 37 | 38 | ```yaml 39 | plugins: 40 | - serverless-newrelic-lambda-layers 41 | ``` 42 | 43 | This plugin should come last in your plugin ordering, particularly if you're also using plugins such as `serverless-plugin-typescript` or `serverless-webpack`. 44 | 45 | If you don't yet have a New Relic account, [sign up here](https://newrelic.com/products/serverless-aws-lambda). 46 | 47 | Grab your [New Relic Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id), 48 | your [New Relic Personal API Key](https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys#personal-api-key) 49 | and plug them into your `serverless.yml`: 50 | 51 | ```yaml 52 | custom: 53 | newRelic: 54 | accountId: your-new-relic-account-id-here 55 | apiKey: your-new-relic-personal-api-key-here 56 | ``` 57 | or 58 | ```yaml 59 | custom: 60 | newRelic: 61 | accountId: your-new-relic-account-id-here 62 | ingestKey: your-new-relic-ingest-key-here 63 | ``` 64 | Deploy: 65 | 66 | ```bash 67 | sls deploy 68 | ``` 69 | 70 | And you're all set. 71 | 72 | ## Usage 73 | 74 | This plugin wraps your handlers without requiring a code change. If you're currently 75 | using a New Relic agent, you can remove the wrapping code you currently have and this plugin will 76 | do it for you automatically. 77 | 78 | - [Node.js Instrumentation Guide](https://docs.newrelic.com/docs/apm/agents/nodejs-agent/getting-started/introduction-new-relic-nodejs) 79 | - [Python Instrumentation Guide](https://docs.newrelic.com/docs/apm/agents/python-agent/getting-started/introduction-new-relic-python) 80 | - [Java Instrumentation Guide](https://docs.newrelic.com/docs/apm/agents/java-agent/getting-started/introduction-new-relic-java) 81 | - [Ruby Instrumentation Guide](https://docs.newrelic.com/docs/apm/agents/ruby-agent/getting-started/introduction-new-relic-ruby) 82 | - [Dotnet Instrumentation Guide](https://docs.newrelic.com/docs/apm/agents/net-agent/getting-started/introduction-new-relic-net) 83 | 84 | Follow the instructions in the guide to implement instrumentation with the [Serverless Framework](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/instrument-lambda-function/instrument-your-own/#serverless) 85 | 86 | 87 | ## Config 88 | 89 | The following config options are available via the `newRelic` section of the `custom` section of your `serverless.yml`: 90 | 91 | #### `accountId` (required) 92 | 93 | Your [New Relic Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id). 94 | 95 | ```yaml 96 | custom: 97 | newRelic: 98 | accountId: your-account-id-here 99 | ``` 100 | 101 | #### `apiKey` (required) 102 | 103 | Your [New Relic Personal API Key](https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys#personal-api-key). 104 | 105 | ```yaml 106 | custom: 107 | newRelic: 108 | apiKey: your-api-key-here 109 | ``` 110 | If your function's source is committed to version control, you can avoid committing your license key by including it in your serverless.yml as a variable. See [the Serverless docs on template variables](https://www.serverless.com/framework/docs/providers/aws/guide/variables/) for more information. 111 | 112 | #### `ingestKey` (required) 113 | 114 | Your [New Relic Personal API Key](https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys#personal-api-key). 115 | 116 | ```yaml 117 | custom: 118 | newRelic: 119 | ingestKey: your-ingest-key-here 120 | ``` 121 | 122 | #### `nrRegion` (required for EU; optional for US) 123 | 124 | If your New Relic account is based in the EU, make sure to specify your nrRegion in the custom block: 125 | 126 | ```yaml 127 | custom: 128 | newRelic: 129 | nrRegion: 'eu' 130 | ``` 131 | 132 | #### `linkedAccount` (optional) 133 | 134 | A label for the New Relic Linked Account. This is how this integration will 135 | appear in New Relic. If not set, it will default to "New Relic Lambda Integration - 136 | ". 137 | 138 | ```yaml 139 | custom: 140 | newRelic: 141 | linkedAccount: your-linked-account-name 142 | ``` 143 | 144 | #### `trustedAccountKey` (optional) 145 | 146 | Only required if your New Relic account is a sub-account. This needs to be the account ID for the root/parent account. 147 | 148 | ```yaml 149 | custom: 150 | newRelic: 151 | trustedAccountKey: your-parent-account-id 152 | ``` 153 | 154 | #### `debug` (optional) 155 | 156 | Whether or not to enable debug mode. Must be a boolean value. This sets the log level to 157 | debug. 158 | 159 | ```yaml 160 | custom: 161 | newRelic: 162 | debug: true 163 | ``` 164 | 165 | #### `enableExtension` (optional) 166 | 167 | Allows your function to deliver its telemetry to New Relic via AWS Lambda Extension. Defaults to `true`, so it can be omitted. To avoid delivering your telemetry via the extension, set to `false`. 168 | 169 | ```yaml 170 | custom: 171 | newRelic: 172 | enableExtension: true 173 | ``` 174 | 175 | #### `sendFunctionLogs` (optional) 176 | 177 | Allows your function to deliver all of your function logs to New Relic via AWS Lambda Extension. The `sendFunctionLogs` config works identically to the older `enableFunctionLogs`. This new config has been introduced for consistency with `sendExtensionLogs`. While the new naming provides improved clarity, `enableFunctionLogs` remains available to ensure backward compatibility. 178 | 179 | ```yaml 180 | custom: 181 | newRelic: 182 | sendFunctionLogs: true 183 | ``` 184 | 185 | #### `sendExtensionLogs` (optional) 186 | Allows your function to deliver all of your `extension logs` to New Relic via AWS Lambda Extension. 187 | 188 | ```yaml 189 | custom: 190 | newRelic: 191 | sendExtensionLogs: true 192 | ``` 193 | 194 | #### `enableFunctionLogs` (optional) 195 | 196 | Allows your function to deliver all of your function logs to New Relic via AWS Lambda Extension. This would eliminate the need for a CloudWatch log subscription + the NR log ingestion Lambda function. This method of log ingestion is lower-cost, and offers faster time to glass. 197 | 198 | ```yaml 199 | custom: 200 | newRelic: 201 | enableFunctionLogs: true 202 | ``` 203 | 204 | #### `enableExtensionLogs` (optional) 205 | 206 | The New Relic Lambda Extension writes diagnostic logs by default. If you'd prefer to mute them, set this to `false`. (Defaults to `true`.) 207 | 208 | ```yaml 209 | custom: 210 | newRelic: 211 | enableExtensionLogs: false 212 | ``` 213 | 214 | 215 | #### `nrTags` (optional) 216 | Specify tags to be added to all log events. Optional. Each tag is composed of a colon-delimited key and value. Multiple key-value pairs are semicolon-delimited; for example, env:prod;team:myTeam. 217 | ```yaml 218 | custom: 219 | newRelic: 220 | nrTags:'env:prod;team:myTeam' 221 | ``` 222 | 223 | #### `nrEnvDelimiter` (optional) 224 | Some users in UTF-8 environments might face difficulty in defining strings of `NR_TAGS` delimited by the semicolon `;` character. Use NR_ENV_DELIMITER, to set custom delimiter for `NR_TAGS`. 225 | ```yaml 226 | custom: 227 | newRelic: 228 | nrEnvDelimiter:',' 229 | ``` 230 | 231 | #### `logEnabled` (optional) 232 | 233 | Enables logging when using CloudWatch-based telemetry transport with the newrelic-log-ingestion Lambda function. Defaults to `false` 234 | 235 | 236 | #### `enableIntegration` (optional) 237 | 238 | Allows the creation of New Relic aws cloud integration when absent. Defaults to `false`. If an integration already exists for your AWS account,you can omit this. 239 | 240 | ```yaml 241 | custom: 242 | newRelic: 243 | enableIntegration: true 244 | ``` 245 | 246 | #### `logLevel` (optional) 247 | 248 | Sets a log level on all functions. Possible values: `'fatal'`, `'error'`, `'warn'`, `'info'`, `'debug'`, `'trace'` or `'silent'`. Defaults to `'error'` 249 | 250 | You can still override log level on a per function basis by configuring environment variable `NEW_RELIC_LOG_LEVEL`. 251 | 252 | ```yaml 253 | custom: 254 | newRelic: 255 | logLevel: debug 256 | ``` 257 | 258 | Logging configuration is considered in the following order: 259 | 260 | 1. function `NEW_RELIC_LOG_LEVEL` environment 261 | 2. provider `NEW_RELIC_LOG_LEVEL` environment 262 | 3. custom newRelic `logLevel` property 263 | 4. custom newRelic `debug` flag 264 | 265 | 266 | #### `manualWrapping` (optional) 267 | 268 | Functions with many dependencies may experience longer cold start times with dynamic wrapping. One possible remediation is to [wrap the function manually](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/enable-lambda-monitoring/enable-serverless-monitoring-aws-lambda-legacy/#node), and bypass the no-code-change wrapping. If you enable this option, you'll need to `require` (or, for ESM, `import`) the New Relic Node Agent, and wrap the body of your handler function. You would still be able to take advantage of the easy installation of the agent via Lambda Layers, and still have telemetry transported to New Relic via the Lambda Extension. We recommend that you include the New Relic Node Agent as a devDependency for local development, and omit it from the dependencies you deploy. Defaults to `false`. 269 | 270 | ```yaml 271 | custom: 272 | newRelic: 273 | manualWrapping: true 274 | ``` 275 | 276 | #### `customRolePolicy` (optional) 277 | 278 | Specify an alternative IAM role policy ARN for this integration here if you do not want to use the default role policy. 279 | 280 | ```yaml 281 | custom: 282 | newRelic: 283 | customRolePolicy: your-custom-role-policy-arn 284 | ``` 285 | 286 | #### `stages` (optional) 287 | 288 | An array of stages that the plugin will be included for. If this key is not specified then all stages will be included. 289 | 290 | ```yaml 291 | custom: 292 | newRelic: 293 | stages: 294 | - prod 295 | ``` 296 | 297 | #### `include` (optional) 298 | 299 | An array of functions to include for automatic wrapping. (You can set `include` or `exclude` options, but not both.) 300 | 301 | ```yaml 302 | custom: 303 | newRelic: 304 | include: 305 | - include-only-func 306 | - another-included-func 307 | ``` 308 | 309 | #### `exclude` (optional) 310 | 311 | An array of functions to exclude from automatic wrapping. (You can set `include` or `exclude` options, but not both.) 312 | 313 | ```yaml 314 | custom: 315 | newRelic: 316 | exclude: 317 | - excluded-func-1 318 | - another-excluded-func 319 | ``` 320 | 321 | #### `layerArn` (optional) 322 | 323 | Pin to a specific layer version. The latest layer ARN is automatically fetched from the [New Relic Layers API](https://layers.newrelic-external.com) 324 | 325 | ```yaml 326 | custom: 327 | newRelic: 328 | layerArn: arn:aws:lambda:us-east-1:451483290750:layer:NewRelicPython37:2 329 | ``` 330 | 331 | #### `slim` (optional) 332 | 333 | slim adds Node.js layer without OpenTelemetry dependencies, resulting in a lighter size. 334 | 335 | ```yaml 336 | custom: 337 | newRelic: 338 | slim: true 339 | ``` 340 | 341 | 342 | #### `cloudWatchFilter` (optional) 343 | 344 | Provide a list of quoted filter terms for the CloudWatch log subscription to the newrelic-log-ingestion Lambda. Combines all terms into an OR filter. Defaults to "NR_LAMBDA_MONITORING" if not set. Use "\*" to capture all logs 345 | 346 | ```yaml 347 | custom: 348 | newRelic: 349 | cloudWatchFilter: 350 | - "NR_LAMBDA_MONITORING" 351 | - "trace this" 352 | - "ERROR" 353 | ``` 354 | 355 | If you want to collect all logs: 356 | 357 | ```yaml 358 | custom: 359 | newRelic: 360 | cloudWatchFilter: "*" 361 | ``` 362 | 363 | Be sure to set the `LOGGING_ENABLED` environment variable to `true` in your log 364 | ingestion function. See the [aws-log-ingestion documentation](https://github.com/newrelic/aws-log-ingestion) for details. 365 | 366 | #### `prepend` (optional) 367 | 368 | Whether or not to prepend the New Relic layer. Defaults to `false` which appends the layer. 369 | 370 | ```yaml 371 | custom: 372 | newRelic: 373 | prepend: true 374 | ``` 375 | 376 | #### `logIngestionFunctionName` (optional) 377 | 378 | Only required if your New Relic log ingestion function name is different from `newrelic-log-ingestion`. 379 | 380 | ```yaml 381 | custom: 382 | newRelic: 383 | logIngestionFunctionName: log-ingestion-service 384 | ``` 385 | 386 | #### `disableAutoSubscription` (optional) 387 | 388 | Only required if you want to disable auto subscription. 389 | 390 | ```yaml 391 | custom: 392 | newRelic: 393 | disableAutoSubscription: true 394 | ``` 395 | 396 | #### `disableLicenseKeySecret` (optional) 397 | 398 | Only required if you want to disable creating license key in AWS Secrets Manager. Setting this as `true` would create NEW_RELIC_LICENSE_KEY environment variable for the New Relic Lambda Extension to access. 399 | 400 | ```yaml 401 | custom: 402 | newRelic: 403 | disableLicenseKeySecret: true 404 | ``` 405 | #### `enableDistributedTracing` (optional) 406 | 407 | Only required if you want to disable distributed tracing. 408 | 409 | ```yaml 410 | custom: 411 | newRelic: 412 | enableDistributedTracing: false 413 | ``` 414 | #### `javaNewRelicHandler` (optional) 415 | 416 | **Java runtimes only**. Only required if you are implementing the `RequestStreamHandler` interface. 417 | Defaults to `RequestHandler` interface. 418 | #### Accepted inputs: 419 | - handleRequest 420 | - handleStreamsRequest 421 | 422 | ```yaml 423 | custom: 424 | newRelic: 425 | javaNewRelicHandler: handleStreamsRequest 426 | ``` 427 | 428 | #### `proxy` (optional) 429 | 430 | This plugin makes various HTTP requests to public APIs in order to retrieve data about the New Relic and cloud provider accounts. If you are behind a proxy when this plugin runs, the HTTP agent needs the proxy information to connect to those APIs. Use the given URL as a proxy for HTTP requests. 431 | 432 | ```yaml 433 | custom: 434 | newRelic: 435 | proxy: http://yourproxy.com:8080 436 | ``` 437 | 438 | ## APM + Serverless Convergence 439 | 440 | [APM + Serverless Convergence](https://docs-preview.newrelic.com/docs/apm-serverless-convergence) enables you to upgrade existing Lambda functions or instrument new functions to monitor them in the New Relic APM interface with minimal effort. 441 | 442 | #### `apm` 443 | Enable `APM Lambda Fusion Mode` 444 | ```yaml 445 | custom: 446 | newRelic: 447 | apm: true 448 | ``` 449 | 450 | #### Provider Tags 451 | 452 | Add `NR.Apm.Lambda.Mode` tag 453 | 454 | ```yaml 455 | provider: 456 | tags: 457 | NR.Apm.Lambda.Mode: true 458 | ``` 459 | 460 | 461 | ## Supported Runtimes 462 | 463 | This plugin currently supports the following AWS runtimes: 464 | 465 | | Runtime | Versions | 466 | |-------------|------------------------| 467 | | Python | `python3.8`, `python3.9`, `python3.10`, `python3.11`, `python3.12`, `python3.13` , `python3.14`| 468 | | Node.js | `nodejs16.x`, `nodejs18.x`, `nodejs20.x`, `nodejs22.x` , `nodejs24.x`| 469 | | .NET | `dotnet3.1`, `dotnet6`, `dotnet8` | 470 | | Java | `java8.al2`, `java11`, `java17`, `java21` | 471 | | Provided | `provided.al2`, `provided.al2023` | 472 | | Ruby | `ruby3.2`, `ruby3.3`, `ruby3.4` | 473 | 474 | ## Contributing 475 | 476 | ### Testing 477 | 478 | 1. Make changes to `examples/nodejs/serverless.yml` based on what you are planning to test 479 | 2. Generate a test case by executing script `generate:test:case` 480 | 481 | ```shell 482 | # Example 483 | npm run generate:test:case 484 | ``` 485 | 486 | 3. Rename generated file `tests/fixtures/example.service.input.json` to test case e.g. `tests/fixtures/log-level.service.input.json` 487 | 4. Create expected output file `tests/fixtures/example.service.output.json` for test case e.g. `tests/fixtures/log-level.service.output.json` 488 | 5. Run tests 489 | 490 | ```shell 491 | # Example 492 | npm run test 493 | ``` --------------------------------------------------------------------------------