Skip to content

Commit 67b8eac

Browse files
committed
otel logger extension
1 parent 356e754 commit 67b8eac

File tree

9 files changed

+95
-13
lines changed

9 files changed

+95
-13
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,29 @@ For production systems you should remove the latency overhead of sending open te
2929
`arn:aws:lambda:${region}:097948374213:layer:baselime-extension-${'x86_64' || 'arm64'}:1`
3030
```
3131

32+
## Adding Custom Events
33+
34+
Our simple but powerful OTEL compatible logging extension lets you add context rich events to your traces. These events can be useful to show more detailed context on errors, add steps that you want recorded for a business process or simply add extra debug information.
35+
36+
```javascript
37+
const { logger } = require("@baselime/lambda-node-opentelemetry");
38+
39+
logger.info("This is an informational message", {
40+
operation: "copy-paste-replace",
41+
count: 9000,
42+
});
43+
```
44+
45+
The extension provides an object that includes four logging functions - info, warn, debug, and error - enabling you to log messages with varying levels of severity. By setting the LOG_LEVEL environment variable, you can control the visibility of the logs.
46+
47+
```javascript
48+
const { logger } = require("@baselime/lambda-node-opentelemetry");
49+
50+
logger.info("This is an informational message", { payload: { foo: "bar" } });
51+
logger.warn("This is a warning message", { payload: { foo: "bar" } });
52+
logger.debug("This is a debug message", { payload: { foo: "bar" } });
53+
logger.error("This is an error message", { payload: { foo: "bar" } });
54+
```
3255
## Manual Installation
3356

3457
Install the `@baselime/lambda-node-opentelemetry` package

examples/sst/stacks/MyStack.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { StackContext, Api, EventBus, App } from "sst/constructs";
22
import { LayerVersion } from "aws-cdk-lib/aws-lambda";
3+
import { Tags } from "aws-cdk-lib";
34

45

56
function magicShit(api) {
@@ -10,7 +11,7 @@ export function API({ stack }: StackContext) {
1011
const baselime = LayerVersion.fromLayerVersionArn(
1112
stack,
1213
"BaselimeLayer",
13-
`arn:aws:lambda:eu-west-2:374211872663:layer:baselime-node:7`
14+
`arn:aws:lambda:eu-west-2:374211872663:layer:baselime-node:8`
1415
);
1516

1617
if (!(stack.node.scope as App)?.local) {
@@ -19,8 +20,9 @@ export function API({ stack }: StackContext) {
1920
AWS_LAMBDA_EXEC_WRAPPER: '/opt/baselime',
2021
BASELIME_KEY: process.env.BASELIME_KEY as string,
2122
COLLECTOR_URL: 'https://otel.baselime.cc/v1',
22-
OTEL_LOG_LEVEL: 'debug',
23-
BASELIME_ORIGINAL_HANDLER: 'packages/functions/src/todo.handler',
23+
24+
BASELIME_ACTUAL_HANDLER: 'packages/functions/src/todo.handler',
25+
2426
});
2527

2628
}
@@ -48,7 +50,7 @@ export function API({ stack }: StackContext) {
4850
},
4951
});
5052

51-
magicShit(api);
53+
Tags.of(api).add("baselime:tracing", "true");
5254

5355
bus.subscribe("todo.created", {
5456
handler: "packages/functions/src/events/todo-created.handler",

handler.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { loadSync } = require('../src/loader');
1+
const { loadSync } = require('./loader');
22

33
exports.handler = function (...args) {
44

handler.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { load } from '../src/loader.js';
2-
import { wrap } from '../src/index.js';
1+
import { load } from './loader.js';
2+
import { wrap } from './index.js';
33

44
export const handler = async function (...args) {
55
const actualHandler = process.env.BASELIME_ACTUAL_HANDLER;

handlers/handler.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { loadSync } = require('../src/loader');
1+
const { loadSync } = require('./loader');
22

33
exports.handler = function (...args) {
44

handlers/handler.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { load } from '../src/loader.js';
2-
import { wrap } from '../src/index.js';
1+
import { load } from './loader.js';
2+
import { wrap } from './index.js';
33

44
export const handler = async function (...args) {
55
const actualHandler = process.env.BASELIME_ACTUAL_HANDLER;

src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import api, { trace, context, propagation, Context as OtelContext, ROOT_CONTEXT,
22
import { Handler } from "aws-lambda";
33
import { flattenObject } from './utils';
44
import { Context } from 'aws-lambda';
5+
export * as logger from './logger';
56

67
declare const global : {
78
baselimeLambdaFlush: () => void;
89
}
910

1011
export function wrap(handler: Handler) {
11-
1212
return async (event: any, lambda_context: Context) => {
1313
const tracer = trace.getTracer('@baselime/baselime-lambda-wrapper', '1');
1414

@@ -117,4 +117,5 @@ function extractContext(event: any) {
117117
);
118118
}
119119
return propagation.extract(api.context.active(), {}, headerGetter);
120-
}
120+
}
121+

src/logger.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { trace, context } from '@opentelemetry/api';
2+
import { flattenObject } from 'utils';
3+
const levels = ['debug', 'info', 'warn', 'error', 'fatal'];
4+
5+
function _log(level: string, message: string, data: Record<string, unknown>) {
6+
if (!_isLogged(level)) return;
7+
if (!levels.includes(level)) {
8+
throw new Error(`Invalid log level ${level}`);
9+
}
10+
11+
const span = trace.getSpan(context.active());
12+
span?.addEvent(message, flattenObject(data));
13+
}
14+
15+
const LOG_LEVEL = process.env.LOG_LEVEL || "INFO";
16+
17+
function _isLogged(level: string) {
18+
if (level === "baselime") {
19+
return true;
20+
}
21+
const levels = ["DEBUG", "INFO", "WARN", "ERROR"];
22+
23+
return levels.indexOf(level.toUpperCase()) >= levels.indexOf(LOG_LEVEL);
24+
}
25+
26+
27+
function getErrorData(data: Record<string, unknown>, err: Error): Record<string, unknown> {
28+
if (!err) {
29+
return data;
30+
}
31+
32+
return {
33+
...(data || {}),
34+
error: {
35+
name: err.name,
36+
message: err.message,
37+
stack: err.stack,
38+
},
39+
};
40+
}
41+
42+
export function info(message: string, data?: Record<string, unknown>) {
43+
_log('info', message, data || {});
44+
}
45+
46+
export function debug(message: string, data?: Record<string, unknown>) {
47+
_log('warn', message, data || {});
48+
}
49+
50+
export function warn(message: string, data?: Record<string, unknown>, err?: Error) {
51+
_log('warn', message, getErrorData(data || {}, err || new Error(message)));
52+
}
53+
54+
export function error(message: string, data?: Record<string, unknown>, err?: Error) {
55+
_log('error', message, getErrorData(data || {}, err || new Error(message)));
56+
}

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @param ob Object The object to flatten
44
* @param prefix String (Optional) The prefix to add before each key, also used for recursion
55
**/
6-
export function flattenObject(ob: Record<string, unknown>, prefix = "", result: Record<string, unknown> = {}) {
6+
export function flattenObject(ob: Record<string, unknown>, prefix = "", result: Record<string, unknown> = {}): Record<string, string | number | boolean> {
77
// Preserve empty objects and arrays, they are lost otherwise
88
if (
99
prefix &&

0 commit comments

Comments
 (0)