Skip to content

Commit 329ff98

Browse files
authored
Merge branch 'main' into dor/add_context_to_publish_batch
2 parents 9a95913 + 8a5c214 commit 329ff98

File tree

9 files changed

+1594
-1296
lines changed

9 files changed

+1594
-1296
lines changed

.github/component_owners.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ components:
8787
plugins/node/opentelemetry-instrumentation-express:
8888
- JamieDanielson
8989
- pkanal
90+
- raphael-theriault-swi
9091
plugins/node/opentelemetry-instrumentation-fastify: []
9192
# Unmaintained
9293
plugins/node/opentelemetry-instrumentation-generic-pool: []
@@ -104,12 +105,12 @@ components:
104105
# Unmaintained
105106
plugins/node/opentelemetry-instrumentation-memcached: []
106107
# Unmaintained
107-
plugins/node/opentelemetry-instrumentation-mongodb: []
108-
# Unmaintained
108+
plugins/node/opentelemetry-instrumentation-mongodb:
109+
- onurtemizkan
109110
plugins/node/opentelemetry-instrumentation-mysql: []
110111
# Unmaintained
111-
plugins/node/opentelemetry-instrumentation-mysql2: []
112-
# Unmaintained
112+
plugins/node/opentelemetry-instrumentation-mysql2:
113+
- raphael-theriault-swi
113114
plugins/node/opentelemetry-instrumentation-nestjs-core: []
114115
# Unmaintained
115116
plugins/node/opentelemetry-instrumentation-net:

detectors/node/opentelemetry-resource-detector-aws/src/detectors/AwsLambdaDetectorSync.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ import {
2222
ResourceDetectionConfig,
2323
} from '@opentelemetry/resources';
2424
import {
25-
ATTR_CLOUD_PROVIDER,
25+
ATTR_AWS_LOG_GROUP_NAMES,
2626
ATTR_CLOUD_PLATFORM,
27+
ATTR_CLOUD_PROVIDER,
2728
ATTR_CLOUD_REGION,
28-
ATTR_FAAS_VERSION,
29+
ATTR_FAAS_INSTANCE,
2930
ATTR_FAAS_NAME,
31+
ATTR_FAAS_MAX_MEMORY,
32+
ATTR_FAAS_VERSION,
3033
CLOUD_PROVIDER_VALUE_AWS,
3134
CLOUD_PLATFORM_VALUE_AWS_LAMBDA,
3235
} from '../semconv';
@@ -38,27 +41,37 @@ import {
3841
*/
3942
export class AwsLambdaDetectorSync implements DetectorSync {
4043
detect(_config?: ResourceDetectionConfig): IResource {
41-
const functionName = process.env.AWS_LAMBDA_FUNCTION_NAME;
42-
if (!functionName) {
44+
// Check if running inside AWS Lambda environment
45+
const executionEnv = process.env.AWS_EXECUTION_ENV;
46+
if (!executionEnv?.startsWith('AWS_Lambda_')) {
4347
return Resource.empty();
4448
}
4549

46-
const functionVersion = process.env.AWS_LAMBDA_FUNCTION_VERSION;
50+
// These environment variables are guaranteed to be present in Lambda environment
51+
// https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime
4752
const region = process.env.AWS_REGION;
53+
const functionName = process.env.AWS_LAMBDA_FUNCTION_NAME;
54+
const functionVersion = process.env.AWS_LAMBDA_FUNCTION_VERSION;
55+
const memorySize = process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE;
56+
57+
// These environment variables are not available in Lambda SnapStart functions
58+
const logGroupName = process.env.AWS_LAMBDA_LOG_GROUP_NAME;
59+
const logStreamName = process.env.AWS_LAMBDA_LOG_STREAM_NAME;
4860

4961
const attributes: ResourceAttributes = {
50-
[ATTR_CLOUD_PROVIDER]: String(CLOUD_PROVIDER_VALUE_AWS),
51-
[ATTR_CLOUD_PLATFORM]: String(CLOUD_PLATFORM_VALUE_AWS_LAMBDA),
62+
[ATTR_CLOUD_PROVIDER]: CLOUD_PROVIDER_VALUE_AWS,
63+
[ATTR_CLOUD_PLATFORM]: CLOUD_PLATFORM_VALUE_AWS_LAMBDA,
64+
[ATTR_CLOUD_REGION]: region,
65+
[ATTR_FAAS_NAME]: functionName,
66+
[ATTR_FAAS_VERSION]: functionVersion,
67+
[ATTR_FAAS_MAX_MEMORY]: parseInt(memorySize!) * 1024 * 1024,
5268
};
53-
if (region) {
54-
attributes[ATTR_CLOUD_REGION] = region;
55-
}
5669

57-
if (functionName) {
58-
attributes[ATTR_FAAS_NAME] = functionName;
70+
if (logGroupName) {
71+
attributes[ATTR_AWS_LOG_GROUP_NAMES] = [logGroupName];
5972
}
60-
if (functionVersion) {
61-
attributes[ATTR_FAAS_VERSION] = functionVersion;
73+
if (logStreamName) {
74+
attributes[ATTR_FAAS_INSTANCE] = logStreamName;
6275
}
6376

6477
return new Resource(attributes);

detectors/node/opentelemetry-resource-detector-aws/src/semconv.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,28 @@ export const ATTR_CONTAINER_NAME = 'container.name';
239239
*/
240240
export const ATTR_FAAS_NAME = 'faas.name';
241241

242+
/**
243+
* The execution environment ID as a string, that will be potentially reused for other invocations to the same function/function version.
244+
*
245+
* @example 2021/06/28/[$LATEST]2f399eb14537447da05ab2a2e39309de
246+
*
247+
* @note * **AWS Lambda:** Use the (full) log stream name.
248+
*
249+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
250+
*/
251+
export const ATTR_FAAS_INSTANCE = 'faas.instance';
252+
253+
/**
254+
* The amount of memory available to the serverless function converted to Bytes.
255+
*
256+
* @example 134217728
257+
*
258+
* @note It's recommended to set this attribute since e.g. too little memory can easily stop a Java AWS Lambda function from working correctly. On AWS Lambda, the environment variable `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` provides this information (which must be multiplied by 1,048,576).
259+
*
260+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
261+
*/
262+
export const ATTR_FAAS_MAX_MEMORY = 'faas.max_memory';
263+
242264
/**
243265
* The immutable version of the function being executed.
244266
*

detectors/node/opentelemetry-resource-detector-aws/test/detectors/AwsLambdaDetector.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ describe('awsLambdaDetector', () => {
3535

3636
describe('on lambda', () => {
3737
it('fills resource', async () => {
38+
process.env.AWS_EXECUTION_ENV = 'AWS_Lambda_nodejs22.x';
3839
process.env.AWS_LAMBDA_FUNCTION_NAME = 'name';
3940
process.env.AWS_LAMBDA_FUNCTION_VERSION = 'v1';
4041
process.env.AWS_REGION = 'us-east-1';

detectors/node/opentelemetry-resource-detector-aws/test/detectors/AwsLambdaDetectorSync.test.ts

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,20 @@
1515
*/
1616

1717
import * as assert from 'assert';
18-
import {
19-
assertCloudResource,
20-
assertEmptyResource,
21-
} from '@opentelemetry/contrib-test-utils';
22-
18+
import { assertEmptyResource } from '@opentelemetry/contrib-test-utils';
2319
import { awsLambdaDetectorSync } from '../../src';
20+
import {
21+
ATTR_AWS_LOG_GROUP_NAMES,
22+
ATTR_CLOUD_PLATFORM,
23+
ATTR_CLOUD_PROVIDER,
24+
ATTR_CLOUD_REGION,
25+
ATTR_FAAS_INSTANCE,
26+
ATTR_FAAS_NAME,
27+
ATTR_FAAS_MAX_MEMORY,
28+
ATTR_FAAS_VERSION,
29+
CLOUD_PROVIDER_VALUE_AWS,
30+
CLOUD_PLATFORM_VALUE_AWS_LAMBDA,
31+
} from '../../src/semconv';
2432

2533
describe('awsLambdaDetectorSync', () => {
2634
let oldEnv: NodeJS.ProcessEnv;
@@ -35,25 +43,54 @@ describe('awsLambdaDetectorSync', () => {
3543

3644
describe('on lambda', () => {
3745
it('fills resource', async () => {
46+
process.env.AWS_EXECUTION_ENV = 'AWS_Lambda_nodejs22.x';
47+
process.env.AWS_REGION = 'us-east-1';
3848
process.env.AWS_LAMBDA_FUNCTION_NAME = 'name';
3949
process.env.AWS_LAMBDA_FUNCTION_VERSION = 'v1';
40-
process.env.AWS_REGION = 'us-east-1';
50+
process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128';
51+
process.env.AWS_LAMBDA_LOG_GROUP_NAME = '/aws/lambda/name';
52+
process.env.AWS_LAMBDA_LOG_STREAM_NAME = '2024/03/14/[$LATEST]123456';
4153

4254
const resource = awsLambdaDetectorSync.detect();
4355

44-
assertCloudResource(resource, {
45-
provider: 'aws',
46-
region: 'us-east-1',
47-
});
48-
49-
assert.strictEqual(resource.attributes['faas.name'], 'name');
50-
assert.strictEqual(resource.attributes['faas.version'], 'v1');
56+
assert.strictEqual(
57+
resource.attributes[ATTR_CLOUD_PROVIDER],
58+
CLOUD_PROVIDER_VALUE_AWS
59+
);
60+
assert.strictEqual(
61+
resource.attributes[ATTR_CLOUD_PLATFORM],
62+
CLOUD_PLATFORM_VALUE_AWS_LAMBDA
63+
);
64+
assert.strictEqual(resource.attributes[ATTR_CLOUD_REGION], 'us-east-1');
65+
assert.strictEqual(resource.attributes[ATTR_FAAS_NAME], 'name');
66+
assert.strictEqual(resource.attributes[ATTR_FAAS_VERSION], 'v1');
67+
assert.strictEqual(
68+
resource.attributes[ATTR_FAAS_INSTANCE],
69+
'2024/03/14/[$LATEST]123456'
70+
);
71+
assert.strictEqual(
72+
resource.attributes[ATTR_FAAS_MAX_MEMORY],
73+
128 * 1024 * 1024
74+
);
75+
assert.deepStrictEqual(resource.attributes[ATTR_AWS_LOG_GROUP_NAMES], [
76+
'/aws/lambda/name',
77+
]);
5178
});
5279
});
5380

5481
describe('not on lambda', () => {
55-
it('returns empty resource', async () => {
56-
process.env.AWS_LAMBDA_FUNCTION_VERSION = 'v1';
82+
it('returns empty resource if AWS_EXECUTION_ENV is not set', async () => {
83+
process.env.AWS_LAMBDA_FUNCTION_NAME = 'name';
84+
process.env.AWS_REGION = 'us-east-1';
85+
86+
const resource = awsLambdaDetectorSync.detect();
87+
88+
assertEmptyResource(resource);
89+
});
90+
91+
it('returns empty resource if AWS_EXECUTION_ENV is not Lambda', async () => {
92+
process.env.AWS_EXECUTION_ENV = 'AWS_ECS_EC2';
93+
process.env.AWS_LAMBDA_FUNCTION_NAME = 'name';
5794
process.env.AWS_REGION = 'us-east-1';
5895

5996
const resource = awsLambdaDetectorSync.detect();

metapackages/auto-instrumentations-node/src/register.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@
1616
import * as opentelemetry from '@opentelemetry/sdk-node';
1717
import { diag, DiagConsoleLogger } from '@opentelemetry/api';
1818
import {
19+
getLogLevelFromEnv,
1920
getNodeAutoInstrumentations,
2021
getResourceDetectorsFromEnv,
2122
} from './utils';
2223

23-
diag.setLogger(
24-
new DiagConsoleLogger(),
25-
opentelemetry.core.getEnv().OTEL_LOG_LEVEL
26-
);
24+
diag.setLogger(new DiagConsoleLogger(), getLogLevelFromEnv());
2725

2826
const sdk = new opentelemetry.NodeSDK({
2927
instrumentations: getNodeAutoInstrumentations(),

metapackages/auto-instrumentations-node/src/utils.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { diag } from '@opentelemetry/api';
17+
import { diag, DiagLogLevel } from '@opentelemetry/api';
1818
import { Instrumentation } from '@opentelemetry/instrumentation';
1919

2020
import { AmqplibInstrumentation } from '@opentelemetry/instrumentation-amqplib';
@@ -136,6 +136,17 @@ const InstrumentationMap = {
136136
'@opentelemetry/instrumentation-winston': WinstonInstrumentation,
137137
};
138138

139+
// The support string -> DiagLogLevel mappings
140+
const logLevelMap: { [key: string]: DiagLogLevel } = {
141+
ALL: DiagLogLevel.ALL,
142+
VERBOSE: DiagLogLevel.VERBOSE,
143+
DEBUG: DiagLogLevel.DEBUG,
144+
INFO: DiagLogLevel.INFO,
145+
WARN: DiagLogLevel.WARN,
146+
ERROR: DiagLogLevel.ERROR,
147+
NONE: DiagLogLevel.NONE,
148+
};
149+
139150
const defaultExcludedInstrumentations = [
140151
'@opentelemetry/instrumentation-fs',
141152
'@opentelemetry/instrumentation-fastify',
@@ -293,3 +304,16 @@ export function getResourceDetectorsFromEnv(): Array<Detector | DetectorSync> {
293304
return resourceDetector || [];
294305
});
295306
}
307+
308+
export function getLogLevelFromEnv(): DiagLogLevel {
309+
const rawLogLevel = process.env.OTEL_LOG_LEVEL;
310+
311+
// NOTE: as per specification we should actually only register if something is set, but our previous implementation
312+
// always registered a logger, even when nothing was set. Falling back to 'INFO' here to keep the same behavior as
313+
// with previous implementations.
314+
// Also: no point in warning - no logger is registered yet
315+
return (
316+
logLevelMap[rawLogLevel?.trim().toUpperCase() ?? 'INFO'] ??
317+
DiagLogLevel.INFO
318+
);
319+
}

metapackages/auto-instrumentations-node/test/utils.test.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { diag } from '@opentelemetry/api';
17+
import { diag, DiagLogLevel } from '@opentelemetry/api';
1818
import { HttpInstrumentationConfig } from '@opentelemetry/instrumentation-http';
1919
import * as assert from 'assert';
2020
import * as sinon from 'sinon';
2121
import { getNodeAutoInstrumentations } from '../src';
22-
import { getResourceDetectorsFromEnv } from '../src/utils';
22+
import { getLogLevelFromEnv, getResourceDetectorsFromEnv } from '../src/utils';
2323

2424
describe('utils', () => {
2525
describe('getNodeAutoInstrumentations', () => {
@@ -223,4 +223,44 @@ describe('utils', () => {
223223
delete process.env.OTEL_NODE_RESOURCE_DETECTORS;
224224
});
225225
});
226+
227+
describe('getLogLevelFromEnv', function () {
228+
afterEach(function () {
229+
delete process.env.OTEL_LOG_LEVEL;
230+
});
231+
232+
it('should select log level based on env var', function () {
233+
process.env.OTEL_LOG_LEVEL = 'NONE';
234+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.NONE);
235+
process.env.OTEL_LOG_LEVEL = 'VERBOSE';
236+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.VERBOSE);
237+
process.env.OTEL_LOG_LEVEL = 'DEBUG';
238+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.DEBUG);
239+
process.env.OTEL_LOG_LEVEL = 'INFO';
240+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.INFO);
241+
process.env.OTEL_LOG_LEVEL = 'WARN';
242+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.WARN);
243+
process.env.OTEL_LOG_LEVEL = 'ERROR';
244+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.ERROR);
245+
process.env.OTEL_LOG_LEVEL = 'ALL';
246+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.ALL);
247+
});
248+
249+
it('should ignore casing', function () {
250+
process.env.OTEL_LOG_LEVEL = 'warn';
251+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.WARN);
252+
process.env.OTEL_LOG_LEVEL = 'WaRN';
253+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.WARN);
254+
});
255+
256+
it('should fall back to INFO on bogus input', function () {
257+
process.env.OTEL_LOG_LEVEL = 'bogus';
258+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.INFO);
259+
});
260+
261+
it('should use INFO when unset', function () {
262+
delete process.env.OTEL_LOG_LEVEL;
263+
assert.strictEqual(getLogLevelFromEnv(), DiagLogLevel.INFO);
264+
});
265+
});
226266
});

0 commit comments

Comments
 (0)