Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
dist
dist-layer
coverage
.github
.git
.layers
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
node_modules
dist
yarn-error.log
coverage
coverage
.layers
.DS_Store
22 changes: 22 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
ARG image
FROM $image

# Create the directory structure required for AWS Lambda Layer
RUN mkdir -p /nodejs/node_modules/

# Install dev dependencies
COPY . datadog-lambda-js
WORKDIR /datadog-lambda-js
RUN yarn install

# Build the lambda layer
RUN yarn build
RUN cp -r dist /nodejs/node_modules/datadog-lambda-js
RUN rm -rf node_modules


# Copy the production dependencies to the modules folder
RUN yarn install --production=true
RUN cp -rf node_modules/* /nodejs/node_modules
# Remove the AWS SDK, which is installed in the lambda by default
RUN rm -rf /nodejs/node_modules/aws-sdk
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
{
"name": "dd-lambda-js",
"name": "datadog-lambda-layer-js",
"version": "0.0.1",
"description": "Lambda client library that supports datadog tracing in node",
"main": "dist/index.js",
"repository": "github.com/DataDog/dd-lambda-js",
"author": "DataDog",
"repository": "github.com/DataDog/datadog-lambda-layer-js",
"author": "Datadog",
"license": "Apache-2.0",
"scripts": {
"build": "tsc",
"test": "jest",
"test:watch": "jest --watch",
"bundle-layer": "webpack --mode=production",
"lint": "tslint --project tsconfig.json"
},
"devDependencies": {
"@types/aws-lambda": "^8.10.26",
"@types/bignumber.js": "^5.0.0",
"@types/jest": "^24.0.13",
"@types/nock": "^10.0.3",
"@types/node": "^12.0.3",
"@types/node": "^12.0.4",
"@types/semver": "^6.0.0",
"@types/shimmer": "^1.0.1",
"jest": "^24.8.0",
Expand Down
5 changes: 5 additions & 0 deletions scripts/Dockerfile_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ARG image
FROM $image
COPY . .
RUN yarn install
RUN yarn build
52 changes: 52 additions & 0 deletions scripts/build_layers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash

# Unless explicitly stated otherwise all files in this repository are licensed
# under the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2019 Datadog, Inc.

# Builds Datadog node layers for lambda functions, using Docker
set -e

LAYER_DIR=".layers"
LAYER_FILES_PREFIX="datadog_lambda_node"
NODE_VERSIONS=("8.10" "10.15")

function make_path_absolute {
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
}

function docker_build_zip {
# Args: [node version] [zip destination]

destination=$(make_path_absolute $2)

# Install datadog node in a docker container to avoid the mess from switching
# between different node runtimes.
temp_dir=$(mktemp -d)
docker build -t datadog-lambda-layer-node:$1 . --no-cache \
--build-arg image=node:$1-alpine

# Run the image by runtime tag, tar its generatd `node` directory to sdout,
# then extract it to a temp directory.
docker run --rm datadog-lambda-layer-node:$1 tar cf - /nodejs | tar -xf - -C $temp_dir

# Zip to destination, and keep directory structure as based in $temp_dir
(cd $temp_dir && zip -q -r $destination ./)

rm -rf $temp_dir
echo "Done creating archive $destination"
}

rm -rf $LAYER_DIR
mkdir $LAYER_DIR

for node_version in "${NODE_VERSIONS[@]}"
do
echo "Building layer for node${node_version}"
docker_build_zip ${node_version} $LAYER_DIR/${LAYER_FILES_PREFIX}${node_version}.zip
done


echo "Done creating layers:"
ls $LAYER_DIR | xargs -I _ echo "$LAYER_DIR/_"
57 changes: 57 additions & 0 deletions scripts/list_layers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/bash

# Unless explicitly stated otherwise all files in this repository are licensed
# under the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2019 Datadog, Inc.

# Lists most recent layers ARNs across regions to STDOUT
# Optionals args: [layer-name] [region]

set -e

LAYER_NAMES=("Datadog-Node8-10" "Datadog-Node10-x")
AVAILABLE_REGIONS=(us-east-2 us-east-1 us-west-1 us-west-2 ap-south-1 ap-northeast-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 ca-central-1 eu-central-1 eu-west-1 eu-west-2 eu-west-3 sa-east-1)

# Check region arg
if [ -z "$2" ]; then
>&2 echo "Region parameter not specified, running for all available regions."
REGIONS=("${AVAILABLE_REGIONS[@]}")
else
>&2 echo "Region parameter specified: $2"
if [[ ! " ${AVAILABLE_REGIONS[@]} " =~ " ${2} " ]]; then
>&2 echo "Could not find $2 in available regions: ${AVAILABLE_REGIONS[@]}"
>&2 echo ""
>&2 echo "EXITING SCRIPT."
return 1
fi
REGIONS=($2)
fi

# Check region arg
if [ -z "$1" ]; then
>&2 echo "Layer parameter not specified, running for all layers "
LAYERS=("${LAYER_NAMES[@]}")
else
>&2 echo "Layer parameter specified: $1"
if [[ ! " ${LAYER_NAMES[@]} " =~ " ${1} " ]]; then
>&2 echo "Could not find $1 in layers: ${LAYER_NAMES[@]}"
>&2 echo ""
>&2 echo "EXITING SCRIPT."
return 1
fi
LAYERS=($1)
fi

for region in "${REGIONS[@]}"
do
for layer_name in "${LAYERS[@]}"
do
last_layer_arn=$(aws lambda list-layer-versions --layer-name $layer_name --region $region | jq -r ".LayerVersions | .[0] | .LayerVersionArn")
if [ -z $last_layer_arn ]; then
>&2 echo "No layer found for $region, $layer_name"
else
echo $last_layer_arn
fi
done
done
75 changes: 75 additions & 0 deletions scripts/publish_layers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash

# Unless explicitly stated otherwise all files in this repository are licensed
# under the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2019 Datadog, Inc.

# Publish the datadog node lambda layer across regions, using the AWS CLI
# Usage: publish_layer.sh [region]
# Specifying the region arg will publish the layer for the single specified region
set -e

NODE_VERSIONS_FOR_AWS_CLI=("nodejs8.10" "nodejs10.x")
LAYER_PATHS=(".layers/datadog_lambda_node8.10.zip" ".layers/datadog_lambda_node10.15.zip")
LAYER_NAMES=("Datadog-Node8-10" "Datadog-Node10-x")
AVAILABLE_REGIONS=(us-east-2 us-east-1 us-west-1 us-west-2 ap-south-1 ap-northeast-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 ca-central-1 eu-central-1 eu-west-1 eu-west-2 eu-west-3 sa-east-1)

# Check that the layer files exist
for layer_file in "${LAYER_PATHS[@]}"
do
if [ ! -f $layer_file ]; then
echo "Could not find $layer_file."
exit 1
fi
done

# Check region arg
if [ -z "$1" ]; then
echo "Region parameter not specified, running for all available regions."
REGIONS=("${AVAILABLE_REGIONS[@]}")
else
echo "Region parameter specified: $1"
if [[ ! " ${AVAILABLE_REGIONS[@]} " =~ " ${1} " ]]; then
echo "Could not find $1 in available regions: ${AVAILABLE_REGIONS[@]}"
echo ""
echo "EXITING SCRIPT."
exit 1
fi
REGIONS=($1)
fi

echo "Starting publishing layers for regions: ${REGIONS[*]}"

for region in "${REGIONS[@]}"
do
echo "Starting publishing layer for region $region..."

# Publish the layers for each version of node
i=0
for layer_name in "${LAYER_NAMES[@]}"; do
aws_version_key="${NODE_VERSIONS_FOR_AWS_CLI[$i]}"
layer_path="${LAYER_PATHS[$i]}"

version_nbr=$(aws lambda publish-layer-version --layer-name $layer_name \
--description "Datadog Lambda Layer for Node" \
--zip-file "fileb://$layer_path" \
--region $region \
--compatible-runtimes $aws_version_key \
| jq -r '.Version')

aws lambda add-layer-version-permission --layer-name $layer_name \
--version-number $version_nbr \
--statement-id "release-$version_nbr" \
--action lambda:GetLayerVersion --principal "*" \
--region $region

echo "Published layer for region $region, node version $aws_version_key, layer_name $layer_name, layer_version $version_nbr"

i=$(expr $i + 1)

done

done

echo "Done !"
24 changes: 24 additions & 0 deletions scripts/run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash

# Unless explicitly stated otherwise all files in this repository are licensed
# under the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2019 Datadog, Inc.

# Run unit tests in Docker
set -e

NODE_VERSIONS=("10.15" "8.10")

for node_version in "${NODE_VERSIONS[@]}"
do
echo "Running tests against node${node_version}"
docker build -t datadog-lambda-layer-node-test:$node_version \
-f scripts/Dockerfile_test . \
--quiet \
--build-arg image=node:$node_version-alpine
docker run --rm -v `pwd`:/datadog-lambda-layer-node \
-w /datadog-lambda-layer-node \
datadog-lambda-layer-node-test:$node_version \
yarn test
done
65 changes: 65 additions & 0 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import http from "http";

import { datadog } from "./index";

const nock = require("nock");

describe("datadog", () => {
let traceId: string | undefined;
let parentId: string | undefined;
let sampled: string | undefined;

const handler = (ev: any) => {
// Mocks out the call

const req = http.get("http://www.example.com");
traceId = req.getHeader("x-datadog-trace-id") as string;
parentId = req.getHeader("x-datadog-parent-id") as string;
sampled = req.getHeader("x-datadog-sampling-priority") as string;
};
beforeEach(() => {
traceId = undefined;
parentId = undefined;
sampled = undefined;
});
it("patches http request when autoPatch enabled", () => {
nock("http://www.example.com")
.get("/")
.reply(200, {});
datadog(handler)(
{
headers: {
"x-datadog-parent-id": "9101112",
"x-datadog-sampling-priority": "2",
"x-datadog-trace-id": "123456",
},
},
{} as any,
() => {},
);

expect(traceId).toEqual("123456");
expect(parentId).toEqual("9101112");
expect(sampled).toEqual("2");
});
it("doesn't patch http request when autoPatch is disabled", () => {
nock("http://www.example.com")
.get("/")
.reply(200, {});
datadog(handler, { autoPatchHTTP: false })(
{
headers: {
"x-datadog-parent-id": "9101112",
"x-datadog-sampling-priority": "2",
"x-datadog-trace-id": "123456",
},
},
{} as any,
() => {},
);

expect(traceId).toBeUndefined();
expect(parentId).toBeUndefined();
expect(sampled).toBeUndefined();
});
});
18 changes: 11 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Handler } from "aws-lambda";

import { extractTraceContext, patchHttp, TraceContextService } from "./trace";
import { extractTraceContext, patchHttp, TraceContextService, unpatchHttp } from "./trace";

/**
* Configuration options for Datadog's lambda wrapper.
Expand Down Expand Up @@ -34,15 +34,19 @@ export function datadog<TEvent, TResult>(
config?: Partial<Config>,
): Handler<TEvent, TResult> {
const finalConfig = getConfig(config);
const contextService = new TraceContextService();

if (finalConfig.autoPatchHTTP) {
patchHttp(contextService);
}

return (event, context, callback) => {
const contextService = new TraceContextService();
if (finalConfig.autoPatchHTTP) {
patchHttp(contextService);
}
contextService.rootTraceContext = extractTraceContext(event);
return handler(event, context, callback);

const result = handler(event, context, callback);
if (finalConfig.autoPatchHTTP) {
unpatchHttp();
}
return result;
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/trace/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { patchHttp } from "./patch-http";
export { patchHttp, unpatchHttp } from "./patch-http";
export { extractTraceContext } from "./context";
export { TraceContextService } from "./trace-context-service";
Loading