Skip to content

Commit ffcb2a2

Browse files
chore: test ddb rds with different flavors (#46)
1 parent e8ec8e7 commit ffcb2a2

20 files changed

Lines changed: 1140 additions & 16 deletions

.github/workflows/ci.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name: CI
33
on:
44
pull_request:
55
branches: [main, master]
6+
types: [opened, synchronize, reopened, ready_for_review]
67

78
concurrency:
89
group: ${{ github.workflow }}-${{ github.head_ref }}
@@ -19,6 +20,7 @@ env:
1920
jobs:
2021
fmt:
2122
name: Format
23+
if: github.event.pull_request.draft == false
2224
runs-on: ubuntu-latest
2325
steps:
2426
- uses: actions/checkout@v4
@@ -29,6 +31,7 @@ jobs:
2931

3032
test:
3133
name: Test
34+
if: github.event.pull_request.draft == false
3235
runs-on: ubuntu-latest
3336
steps:
3437
- uses: actions/checkout@v4
@@ -38,6 +41,7 @@ jobs:
3841

3942
python-distro-test:
4043
name: Python Distro Unit Tests
44+
if: github.event.pull_request.draft == false
4145
runs-on: ubuntu-latest
4246
steps:
4347
- uses: actions/checkout@v4
@@ -54,6 +58,7 @@ jobs:
5458

5559
node-distro-test:
5660
name: Node Distro Unit Tests
61+
if: github.event.pull_request.draft == false
5762
runs-on: ubuntu-latest
5863
steps:
5964
- uses: actions/checkout@v4
@@ -71,6 +76,7 @@ jobs:
7176

7277
build:
7378
name: Build Rust Binaries
79+
if: github.event.pull_request.draft == false
7480
uses: ./.github/workflows/build.yml
7581

7682
deploy:
@@ -106,6 +112,15 @@ jobs:
106112
with:
107113
role-to-assume: ${{ vars.AWS_ROLE_ARN }}
108114
aws-region: ${{ vars.AWS_REGION }}
115+
- name: Free disk space
116+
run: |
117+
sudo rm -rf /usr/share/dotnet
118+
sudo rm -rf /usr/local/lib/android
119+
sudo rm -rf /opt/ghcrunner
120+
sudo rm -rf /usr/local/share/boost
121+
sudo rm -rf /usr/share/swift
122+
docker system prune -af
123+
df -h
109124
- name: Install dependencies
110125
working-directory: integration-tests/iac
111126
run: npm ci
@@ -114,6 +129,8 @@ jobs:
114129
run: npm run deploy
115130
env:
116131
DASH0_DEV_API_TOKEN: ${{ secrets.DASH0_DEV_API_TOKEN }}
132+
TEST_POSTGRESS_PASSWORD: ${{ secrets.TEST_POSTGRESS_PASSWORD }}
133+
TEST_MYSQL_PASSWORD: ${{ secrets.TEST_MYSQL_PASSWORD }}
117134
RESOURCE_PREFIX: ${{ env.RESOURCE_PREFIX }}
118135
- name: Install test dependencies
119136
working-directory: integration-tests/tests

.github/workflows/cleanup-pr.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ jobs:
3333
run: npx cdk destroy ${RESOURCE_PREFIX}IntegrationTestsStack --force || true
3434
env:
3535
DASH0_DEV_API_TOKEN: ${{ secrets.DASH0_DEV_API_TOKEN }}
36+
TEST_POSTGRESS_PASSWORD: ${{ secrets.TEST_POSTGRESS_PASSWORD }}
37+
TEST_MYSQL_PASSWORD: ${{ secrets.TEST_MYSQL_PASSWORD }}
3638
- name: Delete PR-specific Lambda layers
3739
run: |
3840
for layer in ${RESOURCE_PREFIX}dash0-extension-python ${RESOURCE_PREFIX}dash0-extension-node ${RESOURCE_PREFIX}dash0-extension-java ${RESOURCE_PREFIX}dash0-extension-manual; do

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,26 @@
22

33
An extension for capturing observability data from AWS Lambda invocations and shipping to Dash0.
44

5-
This extension has four main functionalities:
5+
## Table of Contents
6+
7+
- [Layer ARNs](#layer-arns)
8+
- [Configuration](#configuration)
9+
- [Required](#required)
10+
- [Optional](#optional)
11+
- [Secret Masking](#secret-masking)
12+
- [Manual Instrumentation](#manual-instrumentation)
13+
- [Enrichment Attributes](#enrichment-attributes)
14+
- [Span Attributes](#span-attributes)
15+
- [Log Attributes](#log-attributes)
16+
- [Metrics](#metrics)
17+
- [Dockerized Lambdas](#dockerized-lambdas)
18+
19+
This extension has five main functionalities:
620
1. Enable auto-instrumentation for supported runtimes, which currently include Python, Node, Java.
721
2. Receive traces from auto/manual instrumentations, enrich with data acquired in the extension, and send to Dash0.
822
3. Detect runtime errors such as timeout or out of memory and create synthetic traces for them
923
4. Collect all logs and send to Dash0, correlated with the trace id of the invocation.
24+
5. Create metrics for invocation duration, cold start duration, billed duration, and memory used.
1025

1126

1227
## Layer ARNs
@@ -42,8 +57,6 @@ See the release page for the latest ARNs of the extension layers for each runtim
4257

4358
* `DASH0_REQUEST_TIMEOUT` - Timeout in milliseconds for HTTP requests to the backend. Default: `2000`.
4459

45-
* `DASH0_MAX_EVENT_PAYLOAD` - Maximum size in KB for event payloads (request/response bodies) captured in traces. Payloads exceeding this limit are truncated. Default: `20`.
46-
4760
* `DASH0_CREATE_PAYLOAD_LOG_RECORDS` - When set to `true` (the default), the extension creates log records containing the request and response payloads for the lambda invocation and each client call. Set to `false` to disable. Default: `true`.
4861

4962
* `DASH0_DISABLE_TELEMETRY_LOG_COLLECTION` - When set to `true`, disables collecting logs from the [Lambda Telemetry API](https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html). Default: `false`.
@@ -102,6 +115,16 @@ The following environment variables allow fine-grained control over secret maski
102115
Example: `DASH0_MASK_QUERY_PARAMS='[".*api_key.*", ".*token.*"]'`
103116

104117

118+
## Manual Instrumentation
119+
120+
If you prefer to set up OpenTelemetry instrumentation yourself instead of relying on the extension's auto-instrumentation, you can use the manual layer and point your OTLP exporters to the extension's local endpoint. The extension will receive the telemetry, enrich it, and forward it to Dash0.
121+
122+
1. Add the manual layer to your Lambda function: `arn:aws:lambda:<region>:115813213817:layer:dash0-extension-manual:<version>`.
123+
2. Configure your OTLP trace exporter to send to `http://127.0.0.1:9009/v1/traces`.
124+
3. If exporting metrics, configure your OTLP metric exporter to send to `http://127.0.0.1:9009/v1/metrics`.
125+
4. Make sure to flush all telemetry before the Lambda invocation completes (e.g., in a response hook or before returning the response).
126+
127+
105128
## Enrichment Attributes
106129

107130
The extension enriches telemetry data with additional attributes beyond what the auto-instrumentation provides.

integration-tests/iac/bin/integration-tests.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env node
22
import * as cdk from 'aws-cdk-lib/core';
33
import { IntegrationTestsStack } from '../lib/integration-tests-stack';
4+
import { SharedDbStack } from '../lib/shared-db-stack';
45

56
const prefix = process.env.RESOURCE_PREFIX ?? '';
67
const app = new cdk.App();
@@ -19,3 +20,5 @@ new IntegrationTestsStack(app, `${prefix}IntegrationTestsStack`, {
1920

2021
/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
2122
});
23+
24+
new SharedDbStack(app, 'SharedDbStack');

integration-tests/iac/lambdas/manual/tracing.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ const resource = resourceFromAttributes({
1818

1919
const exporter = new OTLPTraceExporter({
2020
url: `http://127.0.0.1:9009/v1/traces`,
21-
headers: {
22-
Authorization: `Bearer ${process.env.DASH0_TOKEN}`,
23-
},
2421
});
2522

2623
const provider = new NodeTracerProvider({
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import mysql from 'mysql2/promise';
2+
3+
export async function handler(event, context) {
4+
const connection = await mysql.createConnection({
5+
host: process.env.DB_HOST,
6+
port: parseInt(process.env.DB_PORT || '3306'),
7+
database: process.env.DB_NAME,
8+
user: process.env.DB_USER,
9+
password: process.env.DB_PASSWORD,
10+
ssl: { rejectUnauthorized: false },
11+
});
12+
13+
try {
14+
await connection.execute(
15+
`CREATE TABLE IF NOT EXISTS test_entries (
16+
id INT AUTO_INCREMENT PRIMARY KEY,
17+
request_id TEXT NOT NULL,
18+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
19+
)
20+
`);
21+
22+
const [insertResult] = await connection.execute(
23+
'INSERT INTO test_entries (request_id) VALUES (?)',
24+
[context.awsRequestId],
25+
);
26+
27+
const [rows] = await connection.execute(
28+
'SELECT * FROM test_entries WHERE request_id = ?',
29+
[context.awsRequestId],
30+
);
31+
32+
console.log(`Inserted and read back entry for request: ${context.awsRequestId}`);
33+
34+
return {
35+
statusCode: 200,
36+
body: JSON.stringify({
37+
inserted: { id: insertResult.insertId, request_id: context.awsRequestId },
38+
read: rows[0],
39+
}),
40+
};
41+
} finally {
42+
await connection.end();
43+
}
44+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Client } from 'pg';
2+
3+
export async function handler(event, context) {
4+
const client = new Client({
5+
host: process.env.DB_HOST,
6+
port: parseInt(process.env.DB_PORT || '5432'),
7+
database: process.env.DB_NAME,
8+
user: process.env.DB_USER,
9+
password: process.env.DB_PASSWORD,
10+
ssl: { rejectUnauthorized: false },
11+
});
12+
13+
await client.connect();
14+
15+
try {
16+
await client.query(`
17+
CREATE TABLE IF NOT EXISTS test_entries (
18+
id SERIAL PRIMARY KEY,
19+
request_id TEXT NOT NULL,
20+
created_at TIMESTAMPTZ DEFAULT NOW()
21+
)
22+
`);
23+
24+
const insertResult = await client.query(
25+
'INSERT INTO test_entries (request_id) VALUES ($1) RETURNING *',
26+
[context.awsRequestId],
27+
);
28+
29+
const readResult = await client.query(
30+
'SELECT * FROM test_entries WHERE request_id = $1',
31+
[context.awsRequestId],
32+
);
33+
34+
console.log(`Inserted and read back entry for request: ${context.awsRequestId}`);
35+
36+
return {
37+
statusCode: 200,
38+
body: JSON.stringify({
39+
inserted: insertResult.rows[0],
40+
read: readResult.rows[0],
41+
}),
42+
};
43+
} finally {
44+
await client.end();
45+
}
46+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import json
2+
import os
3+
import pymysql
4+
5+
6+
def handler(event, context):
7+
conn = pymysql.connect(
8+
host=os.environ["DB_HOST"],
9+
port=int(os.environ.get("DB_PORT", "3306")),
10+
database=os.environ["DB_NAME"],
11+
user=os.environ["DB_USER"],
12+
password=os.environ["DB_PASSWORD"],
13+
ssl={"ssl": True},
14+
)
15+
16+
try:
17+
with conn.cursor() as cur:
18+
cur.execute(
19+
"""
20+
CREATE TABLE IF NOT EXISTS test_entries (
21+
id INT AUTO_INCREMENT PRIMARY KEY,
22+
request_id TEXT NOT NULL,
23+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
24+
)
25+
"""
26+
)
27+
conn.commit()
28+
29+
cur.execute(
30+
"INSERT INTO test_entries (request_id) VALUES (%s)",
31+
(context.aws_request_id,),
32+
)
33+
conn.commit()
34+
35+
cur.execute(
36+
"SELECT * FROM test_entries WHERE request_id = %s",
37+
(context.aws_request_id,),
38+
)
39+
read = cur.fetchone()
40+
41+
print(f"Inserted and read back entry for request: {context.aws_request_id}")
42+
43+
return {
44+
"statusCode": 200,
45+
"body": json.dumps(
46+
{
47+
"inserted": {"request_id": context.aws_request_id},
48+
"read": str(read),
49+
}
50+
),
51+
}
52+
finally:
53+
conn.close()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import json
2+
import os
3+
import psycopg2
4+
5+
6+
def handler(event, context):
7+
conn = psycopg2.connect(
8+
host=os.environ["DB_HOST"],
9+
port=int(os.environ.get("DB_PORT", "5432")),
10+
dbname=os.environ["DB_NAME"],
11+
user=os.environ["DB_USER"],
12+
password=os.environ["DB_PASSWORD"],
13+
sslmode="require",
14+
)
15+
16+
try:
17+
with conn.cursor() as cur:
18+
cur.execute(
19+
"""
20+
CREATE TABLE IF NOT EXISTS test_entries (
21+
id SERIAL PRIMARY KEY,
22+
request_id TEXT NOT NULL,
23+
created_at TIMESTAMPTZ DEFAULT NOW()
24+
)
25+
"""
26+
)
27+
conn.commit()
28+
29+
cur.execute(
30+
"INSERT INTO test_entries (request_id) VALUES (%s) RETURNING *",
31+
(context.aws_request_id,),
32+
)
33+
inserted = cur.fetchone()
34+
conn.commit()
35+
36+
cur.execute(
37+
"SELECT * FROM test_entries WHERE request_id = %s",
38+
(context.aws_request_id,),
39+
)
40+
read = cur.fetchone()
41+
42+
print(f"Inserted and read back entry for request: {context.aws_request_id}")
43+
44+
return {
45+
"statusCode": 200,
46+
"body": json.dumps(
47+
{
48+
"inserted": str(inserted),
49+
"read": str(read),
50+
}
51+
),
52+
}
53+
finally:
54+
conn.close()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
psycopg2-binary
2+
pymysql

0 commit comments

Comments
 (0)