1- import { trace , context } from "@opentelemetry/api" ;
1+ import { trace , context , logs , SeverityNumber } from "@opentelemetry/api" ;
22
33interface LogLevel {
44 level : string ;
55 priority : number ;
6+ severity : SeverityNumber ;
67}
78
89type LogMetadata = Record < string , string | number | boolean > ;
910
1011const LOG_LEVELS : Record < string , LogLevel > = {
11- error : { level : "error" , priority : 0 } ,
12- warn : { level : "warn" , priority : 1 } ,
13- info : { level : "info" , priority : 2 } ,
14- debug : { level : "debug" , priority : 3 } ,
12+ error : { level : "error" , priority : 0 , severity : SeverityNumber . ERROR } ,
13+ warn : { level : "warn" , priority : 1 , severity : SeverityNumber . WARN } ,
14+ info : { level : "info" , priority : 2 , severity : SeverityNumber . INFO } ,
15+ debug : { level : "debug" , priority : 3 , severity : SeverityNumber . DEBUG } ,
1516} ;
1617
1718class Logger {
1819 private environment : string ;
1920 private currentLogLevel : LogLevel ;
2021 private serviceName : string ;
2122 private serviceVersion : string ;
23+ private otelLogger : ReturnType < ReturnType < typeof logs . getLoggerProvider > [ "getLogger" ] > | null ;
2224
2325 constructor ( ) {
2426 this . environment = process . env . NODE_ENV || "development" ;
@@ -29,6 +31,15 @@ class Logger {
2931 const logLevelName =
3032 process . env . LOG_LEVEL || ( this . environment === "production" ? "info" : "debug" ) ;
3133 this . currentLogLevel = LOG_LEVELS [ logLevelName ] || LOG_LEVELS . info ;
34+
35+ // Get OpenTelemetry logger if available
36+ try {
37+ const loggerProvider = logs . getLoggerProvider ( ) ;
38+ this . otelLogger = loggerProvider . getLogger ( this . serviceName , this . serviceVersion ) ;
39+ } catch ( error ) {
40+ // OpenTelemetry not initialized, fall back to console logging
41+ this . otelLogger = null ;
42+ }
3243 }
3344
3445 private shouldLog ( level : LogLevel ) : boolean {
@@ -117,7 +128,33 @@ class Logger {
117128 logData . error_type = error . name ;
118129 }
119130
120- // Use console methods based on level
131+ // Emit log via OpenTelemetry if available
132+ if ( this . otelLogger ) {
133+ try {
134+ this . otelLogger . emit ( {
135+ severityNumber : level . severity ,
136+ severityText : level . level . toUpperCase ( ) ,
137+ body : message ,
138+ attributes : {
139+ ...meta ,
140+ service_name : this . serviceName ,
141+ service_version : this . serviceVersion ,
142+ environment : this . environment ,
143+ ...( traceContext . trace_id && { trace_id : traceContext . trace_id } ) ,
144+ ...( traceContext . span_id && { span_id : traceContext . span_id } ) ,
145+ ...( error && {
146+ "error.message" : error . message ,
147+ "error.name" : error . name ,
148+ "error.stack" : error . stack ,
149+ } ) ,
150+ } ,
151+ } ) ;
152+ } catch ( err ) {
153+ // If OTEL logging fails, fall back to console
154+ }
155+ }
156+
157+ // Also log to console for CloudWatch (dual output)
121158 const logMessage = JSON . stringify ( logData ) ;
122159 switch ( level . level ) {
123160 case "error" :
0 commit comments