Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions aws-distro-opentelemetry-node-autoinstrumentation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@
"repository": "aws-observability/aws-otel-js-instrumentation",
"scripts": {
"clean": "rimraf build/*",
"compile:tsc": "tsc -p .",
"compile:webpack": "webpack",
"compile": "npm run compile:webpack",
"compile": "tsc -p .",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"create-version": "node -p \"'export const LIB_VERSION = ' + JSON.stringify(require('./package.json').version) + ';'\" > src/version.ts",
Expand Down Expand Up @@ -95,11 +93,8 @@
"proxyquire": "^2.1.3",
"rimraf": "5.0.5",
"sinon": "15.2.0",
"ts-loader": "^9.5.2",
"ts-mocha": "10.0.0",
"typescript": "4.4.4",
"webpack": "^5.98.0",
"webpack-cli": "^6.0.1"
"typescript": "4.4.4"
},
"dependencies": {
"@opentelemetry/api": "1.9.0",
Expand All @@ -115,7 +110,6 @@
"@opentelemetry/instrumentation-aws-sdk": "0.49.0",
"@opentelemetry/otlp-transformer": "0.57.1",
"@opentelemetry/propagator-aws-xray": "1.26.2",
"@opentelemetry/propagator-aws-xray-lambda": "^0.54.0",
"@opentelemetry/resource-detector-aws": "1.12.0",
"@opentelemetry/resources": "1.30.1",
"@opentelemetry/sdk-metrics": "1.30.1",
Expand All @@ -127,7 +121,6 @@
"build/src/**/*.js",
"build/src/**/*.js.map",
"build/src/**/*.d.ts",
"build/src/**/*.d.ts.map",
"build/src/**/*.json"
]
}

This file was deleted.

23 changes: 23 additions & 0 deletions lambda-layer/packages/layer/install-externals.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

set -euf -o pipefail

# Space separated list of external NPM packages
EXTERNAL_PACKAGES=( "import-in-the-middle" )

for EXTERNAL_PACKAGE in "${EXTERNAL_PACKAGES[@]}"
do
echo "Installing external package $EXTERNAL_PACKAGE ..."

PACKAGE_VERSION=$(npm query "#$EXTERNAL_PACKAGE" \
| grep version \
| head -1 \
| awk -F: '{ print $2 }' \
| sed 's/[",]//g')

echo "Resolved version of the external package $EXTERNAL_PACKAGE: $PACKAGE_VERSION"

npm install "$EXTERNAL_PACKAGE@$PACKAGE_VERSION" --prefix ./build/workspace/nodejs --production --ignore-scripts

echo "Installed external package $EXTERNAL_PACKAGE"
done
9 changes: 7 additions & 2 deletions lambda-layer/packages/layer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"prepare": "npm run compile",
"compile": "tsc -p .",
"postcompile": "copyfiles -F 'node_modules/**' build/workspace/nodejs && copyfiles -f 'scripts/*' build/workspace && copyfiles -f 'build/src/*' build/workspace && cd build/workspace && bestzip ../layer.zip *"
"compile": "webpack && ./install-externals.sh",
"postcompile": "copyfiles -f 'src/**/*.mjs' build/workspace && copyfiles -f 'scripts/*' build/workspace && copyfiles -f 'build/src/*' build/workspace && cd build/workspace && bestzip ../layer.zip *"
},
"keywords": [
"awsdistroopentelemetry",
Expand All @@ -34,5 +34,10 @@
],
"dependencies": {
"@aws/aws-distro-opentelemetry-node-autoinstrumentation": "file:../../../aws-distro-opentelemetry-node-autoinstrumentation/aws-aws-distro-opentelemetry-node-autoinstrumentation-0.5.0-dev0.tgz"
},
"devDependencies": {
"ts-loader": "^9.5.2",
"webpack": "^5.98.0",
"webpack-cli": "^6.0.1"
}
}
35 changes: 1 addition & 34 deletions lambda-layer/packages/layer/scripts/otel-instrument
Original file line number Diff line number Diff line change
@@ -1,39 +1,6 @@
#!/bin/bash
_is_esm_handler() {
# Lambda function root directory
TASK_DIR="/var/task"

# Flag variables to track conditions
local found_mjs=false
local is_module=false

# Check for any files ending with `.mjs`
if ls "$TASK_DIR"/*.mjs &>/dev/null; then
found_mjs=true
fi

# Check if `package.json` exists and if it contains `"type": "module"`
if [ -f "$TASK_DIR/package.json" ]; then
# Check for the `"type": "module"` attribute in `package.json`
if grep -q '"type": *"module"' "$TASK_DIR/package.json"; then
is_module=true
fi
fi

# Return true if both conditions are met
if $found_mjs || $is_module; then
return 0 # 0 in bash means true
else
return 1 # 1 in bash means false
fi
}

if _is_esm_handler || [[ ${HANDLER_IS_ESM} == true ]]; then
export NODE_OPTIONS="${NODE_OPTIONS} --import @aws/aws-distro-opentelemetry-node-autoinstrumentation/register --experimental-loader=@opentelemetry/instrumentation/hook.mjs"
export HANDLER_IS_ESM=true
else
export NODE_OPTIONS="${NODE_OPTIONS} --require /opt/wrapper.js"
fi
export NODE_OPTIONS="${NODE_OPTIONS} --import /opt/init.mjs"

export LAMBDA_RESOURCE_ATTRIBUTES="cloud.region=$AWS_REGION,cloud.provider=aws,faas.name=$AWS_LAMBDA_FUNCTION_NAME,faas.version=$AWS_LAMBDA_FUNCTION_VERSION,faas.instance=$AWS_LAMBDA_LOG_STREAM_NAME,aws.log.group.names=$AWS_LAMBDA_LOG_GROUP_NAME";

Expand Down
7 changes: 7 additions & 0 deletions lambda-layer/packages/layer/src/init.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const WRAPPER_INIT_START_TIME = Date.now();
await import('./wrapper.js');
console.log('OpenTelemetry wrapper init completed in', Date.now() - WRAPPER_INIT_START_TIME, 'ms');

const LOADER_INIT_START_TIME = Date.now();
await import('./loader.mjs');
console.log('OpenTelemetry loader init completed in', Date.now() - LOADER_INIT_START_TIME, 'ms');
91 changes: 91 additions & 0 deletions lambda-layer/packages/layer/src/loader.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { register } from 'module';
import * as path from 'path';
import * as fs from 'fs';

function _hasFolderPackageJsonTypeModule(folder) {
if (folder.endsWith('/node_modules')) {
return false;
}
let pj = path.join(folder, '/package.json');
if (fs.existsSync(pj)) {
try {
let pkg = JSON.parse(fs.readFileSync(pj).toString());
if (pkg) {
if (pkg.type === 'module') {
return true;
} else {
return false;
}
}
} catch (e) {
console.warn(`${pj} cannot be read, it will be ignored for ES module detection purposes.`, e);
return false;
}
}
if (folder === '/') {
return false;
}
return _hasFolderPackageJsonTypeModule(path.resolve(folder, '..'));
}

function _hasPackageJsonTypeModule(file) {
let jsPath = file + '.js';
if (fs.existsSync(jsPath)) {
return _hasFolderPackageJsonTypeModule(path.resolve(path.dirname(jsPath)));
}
return false;
}

function _resolveHandlerFileName() {
const taskRoot = process.env.LAMBDA_TASK_ROOT;
const handlerDef = process.env._HANDLER;
if (!taskRoot || !handlerDef) {
return null;
}
const handler = path.basename(handlerDef);
const moduleRoot = handlerDef.substr(0, handlerDef.length - handler.length);
const [module, _] = handler.split('.', 2);
return path.resolve(taskRoot, moduleRoot, module);
}

function _isHandlerAnESModule() {
try {
const handlerFileName = _resolveHandlerFileName();
if (!handlerFileName) {
return false;
}
if (fs.existsSync(handlerFileName + '.mjs')) {
return true;
} else if (fs.existsSync(handlerFileName + '.cjs')) {
return false;
} else {
return _hasPackageJsonTypeModule(handlerFileName);
}
} catch (e) {
console.error('Unknown error occurred while checking whether handler is an ES module', e);
return false;
}
}

let registered = false;

export function registerLoader() {
if (!registered) {
register('import-in-the-middle/hook.mjs', import.meta.url);
registered = true;
}
}

if (_isHandlerAnESModule()) {
/*
We could activate ESM loader hook of the "import-in-the-middle" library,
- by "--loader=import-in-the-middle/hook.mjs" Node CLI option, but "--loader" option has been deprecated
- or by "--import=import-in-the-middle/hook.mjs" Node CLI option, but in this case,
there will always be "import-in-the-middle" hook initialization overhead even for non-ESM (CommonJS) modules

Hence, instead, we initialize "import-in-the-middle" hook only for ES (EcmaScript) based user handlers
to prevent redundant "import-in-the-middle" hook initialization overhead during coldstart
of the CommonJS based user handlers.
*/
registerLoader();
}
11 changes: 11 additions & 0 deletions lambda-layer/packages/layer/tsconfig.webpack.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.esm",
"compilerOptions": {
"rootDir": ".",
"outDir": "build",
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
]
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
const path = require('path');

module.exports = {
entry: './src/register.ts',
entry: './src/wrapper.ts',
target: 'node',
mode: 'production',
externalsPresets: { node: true },
externals: [
'import-in-the-middle',
'@aws-sdk',
],
output: {
path: path.resolve('./build/src'),
filename: 'register.js',
filename: 'wrapper.js',
library: {
type: 'commonjs2',
}
},
resolve: {
extensions: ['.ts', '.js'],
extensions: ['.ts', '.js', '.mjs'],
modules: [
path.resolve('./src'),
'node_modules',
Expand Down
27 changes: 27 additions & 0 deletions lambda-layer/tsconfig.esm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
"moduleResolution": "node",
"module": "es2020",
"target": "es2020",
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"pretty": true,
"sourceMap": true,
"strict": true,
"strictNullChecks": true,
"incremental": true,
"newLine": "LF"
},
"exclude": [
"node_modules"
]
}

Loading
Loading