diff --git a/integration_tests/snapshots/logs/esm_node12.log b/integration_tests/snapshots/logs/esm_node12.log index 0cc84323..267da1f5 100644 --- a/integration_tests/snapshots/logs/esm_node12.log +++ b/integration_tests/snapshots/logs/esm_node12.log @@ -1,5 +1,5 @@ -XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} +XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} { "traces": [ [ @@ -68,7 +68,7 @@ XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportMo ] ] } -XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} +XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} { "traces": [ [ @@ -141,7 +141,7 @@ START Unknown application error occurred Runtime.ImportModuleError END Duration: XXXX ms Memory Used: XXXX MB -XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} +XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} { "traces": [ [ @@ -215,7 +215,7 @@ Unknown application error occurred Runtime.ImportModuleError END Duration: XXXX ms Memory Used: XXXX MB -XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} +XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} { "traces": [ [ @@ -284,7 +284,7 @@ XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportMo ] ] } -XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} +XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} { "traces": [ [ @@ -358,7 +358,7 @@ Unknown application error occurred Runtime.ImportModuleError END Duration: XXXX ms Memory Used: XXXX MB -XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} +XXXX-XX-XX XX:XX:XX.XXX ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'esm'\nRequire stack:\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js\n- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js\n- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/index.js\n- /opt/nodejs/node_modules/datadog-lambda-js/handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'esm'","Require stack:","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js","- /opt/nodejs/node_modules/datadog-lambda-js/runtime/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/listener.js","- /opt/nodejs/node_modules/datadog-lambda-js/trace/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/index.js","- /opt/nodejs/node_modules/datadog-lambda-js/handler.js","- /var/runtime/UserFunction.js","- /var/runtime/index.js"," at ImportModuleError.ExtendedError [as constructor] (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at new ImportModuleError (/opt/nodejs/node_modules/datadog-lambda-js/runtime/errors.js:XXX:XXX)"," at _loadUserAppSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at loadSync (/opt/nodejs/node_modules/datadog-lambda-js/runtime/user-function.js:XXX:XXX)"," at Object. (/opt/nodejs/node_modules/datadog-lambda-js/handler.js:XXX:XXX)"," at Module._compile (internal/modules/cjs/loader.js:XXX:XXX)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.load (internal/modules/cjs/loader.js:XXX:XXX)"," at Function.Module._load (internal/modules/cjs/loader.js:XXX:XXX)"," at Module.require (internal/modules/cjs/loader.js:XXX:XXX)"]} { "traces": [ [ diff --git a/integration_tests/snapshots/logs/process-input-traced_node12.log b/integration_tests/snapshots/logs/process-input-traced_node12.log index 42620e57..dbd718f5 100644 --- a/integration_tests/snapshots/logs/process-input-traced_node12.log +++ b/integration_tests/snapshots/logs/process-input-traced_node12.log @@ -136,6 +136,28 @@ START "start":XXXX, "duration":XXXX, "service": "integration-tests-js-XXXX-process-input-traced_node12" + }, + { + "trace_id":"XXXX", + "span_id":"XXXX", + "parent_id":"XXXX", + "name": "aws.lambda.load", + "resource": "integration-tests-js-XXXX-process-input-traced_node12", + "error": 0, + "meta": { + "service": "aws.lambda", + "runtime-id":"XXXX", + "operation_name": "aws.lambda.require", + "resource_names": "integration-tests-js-XXXX-process-input-traced_node12", + "language": "javascript" + }, + "metrics": { + "process_id":XXXX, + "_sampling_priority_v1": 1 + }, + "start":XXXX, + "duration":XXXX, + "service": "integration-tests-js-XXXX-process-input-traced_node12" } ] ] diff --git a/integration_tests/snapshots/logs/process-input-traced_node14.log b/integration_tests/snapshots/logs/process-input-traced_node14.log index 78b7a925..50d3fbed 100644 --- a/integration_tests/snapshots/logs/process-input-traced_node14.log +++ b/integration_tests/snapshots/logs/process-input-traced_node14.log @@ -136,6 +136,28 @@ START "start":XXXX, "duration":XXXX, "service": "integration-tests-js-XXXX-process-input-traced_node14" + }, + { + "trace_id":"XXXX", + "span_id":"XXXX", + "parent_id":"XXXX", + "name": "aws.lambda.load", + "resource": "integration-tests-js-XXXX-process-input-traced_node14", + "error": 0, + "meta": { + "service": "aws.lambda", + "runtime-id":"XXXX", + "operation_name": "aws.lambda.require", + "resource_names": "integration-tests-js-XXXX-process-input-traced_node14", + "language": "javascript" + }, + "metrics": { + "process_id":XXXX, + "_sampling_priority_v1": 1 + }, + "start":XXXX, + "duration":XXXX, + "service": "integration-tests-js-XXXX-process-input-traced_node14" } ] ] diff --git a/integration_tests/snapshots/logs/process-input-traced_node16.log b/integration_tests/snapshots/logs/process-input-traced_node16.log index 90ebc44f..48ff92aa 100644 --- a/integration_tests/snapshots/logs/process-input-traced_node16.log +++ b/integration_tests/snapshots/logs/process-input-traced_node16.log @@ -140,6 +140,29 @@ START "start":XXXX, "duration":XXXX, "service": "integration-tests-js-XXXX-process-input-traced_node16" + }, + { + "trace_id":"XXXX", + "span_id":"XXXX", + "parent_id":"XXXX", + "name": "aws.lambda.load", + "resource": "integration-tests-js-XXXX-process-input-traced_node16", + "error": 0, + "meta": { + "service": "aws.lambda", + "version": "1.0.0", + "runtime-id":"XXXX", + "operation_name": "aws.lambda.require", + "resource_names": "integration-tests-js-XXXX-process-input-traced_node16", + "language": "javascript" + }, + "metrics": { + "process_id":XXXX, + "_sampling_priority_v1": 1 + }, + "start":XXXX, + "duration":XXXX, + "service": "integration-tests-js-XXXX-process-input-traced_node16" } ] ] diff --git a/integration_tests/snapshots/logs/process-input-traced_node18.log b/integration_tests/snapshots/logs/process-input-traced_node18.log index 1854ad66..b3c80d66 100644 --- a/integration_tests/snapshots/logs/process-input-traced_node18.log +++ b/integration_tests/snapshots/logs/process-input-traced_node18.log @@ -140,6 +140,29 @@ START "start":XXXX, "duration":XXXX, "service": "integration-tests-js-XXXX-process-input-traced_node18" + }, + { + "trace_id":"XXXX", + "span_id":"XXXX", + "parent_id":"XXXX", + "name": "aws.lambda.load", + "resource": "integration-tests-js-XXXX-process-input-traced_node18", + "error": 0, + "meta": { + "service": "aws.lambda", + "version": "1.0.0", + "runtime-id":"XXXX", + "operation_name": "aws.lambda.require", + "resource_names": "integration-tests-js-XXXX-process-input-traced_node18", + "language": "javascript" + }, + "metrics": { + "process_id":XXXX, + "_sampling_priority_v1": 1 + }, + "start":XXXX, + "duration":XXXX, + "service": "integration-tests-js-XXXX-process-input-traced_node18" } ] ] diff --git a/integration_tests/snapshots/logs/status-code-500s_node12.log b/integration_tests/snapshots/logs/status-code-500s_node12.log index 4cefd8e0..2afd522d 100644 --- a/integration_tests/snapshots/logs/status-code-500s_node12.log +++ b/integration_tests/snapshots/logs/status-code-500s_node12.log @@ -96,6 +96,28 @@ START "duration":XXXX, "service": "aws.lambda", "type": "serverless" + }, + { + "trace_id":"XXXX", + "span_id":"XXXX", + "parent_id":"XXXX", + "name": "aws.lambda.load", + "resource": "integration-tests-js-XXXX-status-code-500s_node12", + "error": 0, + "meta": { + "service": "aws.lambda", + "runtime-id":"XXXX", + "operation_name": "aws.lambda.require", + "resource_names": "integration-tests-js-XXXX-status-code-500s_node12", + "language": "javascript" + }, + "metrics": { + "process_id":XXXX, + "_sampling_priority_v1": 1 + }, + "start":XXXX, + "duration":XXXX, + "service": "integration-tests-js-XXXX-status-code-500s_node12" } ] ] diff --git a/integration_tests/snapshots/logs/status-code-500s_node14.log b/integration_tests/snapshots/logs/status-code-500s_node14.log index 5d7e51e5..55fbaf8b 100644 --- a/integration_tests/snapshots/logs/status-code-500s_node14.log +++ b/integration_tests/snapshots/logs/status-code-500s_node14.log @@ -96,6 +96,28 @@ START "duration":XXXX, "service": "aws.lambda", "type": "serverless" + }, + { + "trace_id":"XXXX", + "span_id":"XXXX", + "parent_id":"XXXX", + "name": "aws.lambda.load", + "resource": "integration-tests-js-XXXX-status-code-500s_node14", + "error": 0, + "meta": { + "service": "aws.lambda", + "runtime-id":"XXXX", + "operation_name": "aws.lambda.require", + "resource_names": "integration-tests-js-XXXX-status-code-500s_node14", + "language": "javascript" + }, + "metrics": { + "process_id":XXXX, + "_sampling_priority_v1": 1 + }, + "start":XXXX, + "duration":XXXX, + "service": "integration-tests-js-XXXX-status-code-500s_node14" } ] ] @@ -191,6 +213,7 @@ START } END Duration: XXXX ms Memory Used: XXXX MB START +END Duration: XXXX ms Memory Used: XXXX MB { "e": XXXX, "m": "aws.lambda.enhanced.invocations", @@ -277,4 +300,3 @@ START ] ] } -END Duration: XXXX ms Memory Used: XXXX MB diff --git a/integration_tests/snapshots/logs/status-code-500s_node16.log b/integration_tests/snapshots/logs/status-code-500s_node16.log index 0c4cb637..b1738ac3 100644 --- a/integration_tests/snapshots/logs/status-code-500s_node16.log +++ b/integration_tests/snapshots/logs/status-code-500s_node16.log @@ -98,6 +98,29 @@ START "duration":XXXX, "service": "aws.lambda", "type": "serverless" + }, + { + "trace_id":"XXXX", + "span_id":"XXXX", + "parent_id":"XXXX", + "name": "aws.lambda.load", + "resource": "integration-tests-js-XXXX-status-code-500s_node16", + "error": 0, + "meta": { + "service": "aws.lambda", + "version": "1.0.0", + "runtime-id":"XXXX", + "operation_name": "aws.lambda.require", + "resource_names": "integration-tests-js-XXXX-status-code-500s_node16", + "language": "javascript" + }, + "metrics": { + "process_id":XXXX, + "_sampling_priority_v1": 1 + }, + "start":XXXX, + "duration":XXXX, + "service": "integration-tests-js-XXXX-status-code-500s_node16" } ] ] diff --git a/integration_tests/snapshots/logs/status-code-500s_node18.log b/integration_tests/snapshots/logs/status-code-500s_node18.log index 916415c5..0ee5b706 100644 --- a/integration_tests/snapshots/logs/status-code-500s_node18.log +++ b/integration_tests/snapshots/logs/status-code-500s_node18.log @@ -98,6 +98,29 @@ START "duration":XXXX, "service": "aws.lambda", "type": "serverless" + }, + { + "trace_id":"XXXX", + "span_id":"XXXX", + "parent_id":"XXXX", + "name": "aws.lambda.load", + "resource": "integration-tests-js-XXXX-status-code-500s_node18", + "error": 0, + "meta": { + "service": "aws.lambda", + "version": "1.0.0", + "runtime-id":"XXXX", + "operation_name": "aws.lambda.require", + "resource_names": "integration-tests-js-XXXX-status-code-500s_node18", + "language": "javascript" + }, + "metrics": { + "process_id":XXXX, + "_sampling_priority_v1": 1 + }, + "start":XXXX, + "duration":XXXX, + "service": "integration-tests-js-XXXX-status-code-500s_node18" } ] ] diff --git a/src/index.ts b/src/index.ts index 3e3a25d6..1caaccb2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,7 @@ import { MetricsListener, } from "./metrics"; import { TraceConfig, TraceHeaders, TraceListener } from "./trace"; +import { subscribeToDC } from "./runtime"; import { logDebug, logError, @@ -36,6 +37,9 @@ export const traceExtractorEnvVar = "DD_TRACE_EXTRACTOR"; export const defaultSiteURL = "datadoghq.com"; export const encodeAuthorizerContextEnvVar = "DD_ENCODE_AUTHORIZER_CONTEXT"; export const decodeAuthorizerContextEnvVar = "DD_DECODE_AUTHORIZER_CONTEXT"; +export const coldStartTracingEnvVar = "DD_COLD_START_TRACING"; +export const minColdStartTraceDurationEnvVar = "DD_MIN_COLD_START_DURATION"; +export const coldStartTraceSkipLibEnvVar = "DD_COLD_START_TRACE_SKIP_LIB"; interface GlobalConfig { /** @@ -75,11 +79,16 @@ export const defaultConfig: Config = { mergeDatadogXrayTraces: false, shouldRetryMetrics: false, siteURL: "", + minColdStartTraceDuration: 3, + coldStartTraceSkipLib: "", } as const; let currentMetricsListener: MetricsListener | undefined; let currentTraceListener: TraceListener | undefined; +if (getEnvValue(coldStartTracingEnvVar, "true")) { + subscribeToDC(); +} /** * Wraps your AWS lambda handler functions to add tracing/metrics support * @param handler A lambda handler function. @@ -120,7 +129,7 @@ export function datadog( currentTraceListener = traceListener; try { - await traceListener.onStartInvocation(event, context); + traceListener.onStartInvocation(event, context); await metricsListener.onStartInvocation(event); if (finalConfig.enhancedMetrics) { incrementInvocationsMetric(metricsListener, context); @@ -287,6 +296,14 @@ function getConfig(userConfig?: Partial): Config { config.decodeAuthorizerContext = result === "true"; } + if (userConfig === undefined || userConfig.minColdStartTraceDuration === undefined) { + config.minColdStartTraceDuration = Number(getEnvValue(minColdStartTraceDurationEnvVar, "3")); + } + + if (userConfig === undefined || userConfig.minColdStartTraceDuration === undefined) { + config.coldStartTraceSkipLib = getEnvValue(coldStartTraceSkipLibEnvVar, "./opentracing/tracer"); + } + return config; } diff --git a/src/runtime/index.ts b/src/runtime/index.ts index d55f827f..cf085cf6 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -1 +1,2 @@ export { load, loadSync } from "./user-function"; +export { subscribeToDC, getTraceTree, RequireNode } from "./require-tracer" diff --git a/src/runtime/require-tracer.spec.ts b/src/runtime/require-tracer.spec.ts new file mode 100644 index 00000000..214d9f9a --- /dev/null +++ b/src/runtime/require-tracer.spec.ts @@ -0,0 +1,29 @@ +import { subscribeToDC, getTraceTree, RequireNode } from "./require-tracer"; +const dc = require('diagnostics_channel') + +describe('require-tracer', () => { + it('generates a trace tree', () => { + subscribeToDC() + const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart') + const moduleLoadEndChannel = dc.channel('dd-trace:moduleLoadEnd') + + // require('myLibrary') + moduleLoadStartChannel.publish({ + request: 'myLibrary' + }) + // require('myChildLibrary') + moduleLoadStartChannel.publish({ + request: 'myChildLibrary' + }) + moduleLoadEndChannel.publish() + moduleLoadEndChannel.publish() + const res = getTraceTree() + expect(res).toBeDefined + expect(res[0].id).toBe('myLibrary') + const resChildren = res[0].children as RequireNode[] + expect(resChildren).toHaveLength(1) + const resChild = resChildren.pop() as RequireNode + expect(resChild.id).toBe('myChildLibrary') + }) + +}) diff --git a/src/runtime/require-tracer.ts b/src/runtime/require-tracer.ts new file mode 100644 index 00000000..6db2e163 --- /dev/null +++ b/src/runtime/require-tracer.ts @@ -0,0 +1,58 @@ +const dc = require('diagnostics_channel') + +export class RequireNode { + public id: string + public filename: string + public startTime: number + public endTime: number + public children: RequireNode[] + + constructor(id: string, filename: string, startTime: number) { + this.id = id + this.filename = filename + this.startTime = startTime + this.endTime = startTime + this.children = [] + } + + public set setEnd(endTime: number) { + this.endTime = endTime + } +} + +const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart') +const moduleLoadEndChannel = dc.channel('dd-trace:moduleLoadEnd') +const rootNodes: RequireNode[] = [] + +const requireStack: RequireNode[] = [] +const pushNode = (data: any) => { + const startTime = Date.now() + + const reqNode = new RequireNode(data.request, data.filename, startTime) + const maybeParent = requireStack[requireStack.length - 1] + + if (maybeParent) { + maybeParent.children.push(reqNode) + } + requireStack.push(reqNode) +} + +const popNode = () => { + const endTime = Date.now() + const reqNode = requireStack.pop() + if (reqNode){ + reqNode.endTime = endTime + } + if (requireStack.length <= 0 && reqNode) { + rootNodes.push(reqNode) + } +} + +export const subscribeToDC = () => { + moduleLoadStartChannel.subscribe(pushNode) + moduleLoadEndChannel.subscribe(popNode) +} + +export const getTraceTree = (): RequireNode[] => { + return rootNodes +} diff --git a/src/runtime/user-function.ts b/src/runtime/user-function.ts index b9243bf8..5071238f 100644 --- a/src/runtime/user-function.ts +++ b/src/runtime/user-function.ts @@ -18,8 +18,7 @@ import { MalformedHandlerName, ImportModuleError, UserCodeSyntaxError, -} from "./errors.js"; -import { logDebug } from "../utils/log.js"; +} from "./errors"; const module_importer = require("./module_importer"); const FUNCTION_EXPR = /^([^.]*)\.(.*)$/; @@ -340,4 +339,4 @@ export const loadSync = function ( } return handlerFunc; -}; \ No newline at end of file +}; diff --git a/src/trace/cold-start-tracer.spec.ts b/src/trace/cold-start-tracer.spec.ts new file mode 100644 index 00000000..c99848a1 --- /dev/null +++ b/src/trace/cold-start-tracer.spec.ts @@ -0,0 +1,197 @@ +import { RequireNode } from "../runtime/require-tracer"; +import { ColdStartTracerConfig, ColdStartTracer } from "./cold-start-tracer"; +import { TracerWrapper, SpanOptions } from "./tracer-wrapper"; +import { SpanWrapper } from "./span-wrapper"; + +let mockStartSpan: jest.Mock; +let mockFinishSpan: jest.Mock; + +jest.mock("./tracer-wrapper", () => { + mockFinishSpan = jest.fn(); + mockStartSpan = jest.fn().mockImplementation((spanName, spanOptions) => { + return { spanName, spanOptions, finish: mockFinishSpan }; + }); + class MockTraceWrapper { + get isTraceAvailable() { + return true; + } + + constructor() {} + + startSpan(spanName: string, spanOptions: SpanOptions): any { + return mockStartSpan(spanName, spanOptions); + } + } + return { + TracerWrapper: MockTraceWrapper, + }; +}); + +describe("ColdStartTracer", () => { + beforeEach(() => { + mockStartSpan.mockClear(); + mockFinishSpan.mockClear(); + }); + + it("generates a trace tree", () => { + const requireNodes: RequireNode[] = [ + { + id: "handler", + filename: "/var/task/handler.js", + startTime: 1, + endTime: 6, + children: [ + { + id: "myChildModule", + filename: "/opt/nodejs/node_modules/my-child-module.js", + startTime: 2, + endTime: 3, + }, + { + id: "myCoreModule", + filename: "http", + startTime: 4, + endTime: 5, + }, + { + id: "aws-sdk", + filename: "/var/runtime/aws-sdk", + startTime: 4, + endTime: 5, + }, + ], + } as any as RequireNode, + ]; + const coldStartConfig: ColdStartTracerConfig = { + tracerWrapper: new TracerWrapper(), + parentSpan: { + span: {}, + name: "my-lambda-span", + } as any as SpanWrapper, + lambdaFunctionName: "my-function-name", + coldStartSpanFinishTime: 500, + minDuration: 1, + ignoreLibs: "", + }; + const coldStartTracer = new ColdStartTracer(coldStartConfig); + coldStartTracer.trace(requireNodes); + expect(mockStartSpan).toHaveBeenCalledTimes(5); + expect(mockFinishSpan).toHaveBeenCalledTimes(5); + const span1 = mockStartSpan.mock.calls[0]; + expect(span1[0]).toEqual("aws.lambda.load"); + expect(span1[1].tags).toEqual({ + operation_name: "aws.lambda.require", + "resource.name": "my-function-name", + resource_names: "my-function-name", + service: "aws.lambda", + }); + const span2 = mockStartSpan.mock.calls[1]; + expect(span2[0]).toEqual("aws.lambda.require"); + expect(span2[1].tags).toEqual({ + operation_name: "aws.lambda.require", + "resource.name": "handler", + resource_names: "handler", + service: "aws.lambda", + filename: "/var/task/handler.js", + }); + const span3 = mockStartSpan.mock.calls[2]; + expect(span3[0]).toEqual("aws.lambda.require_layer"); + expect(span3[1].tags).toEqual({ + filename: "/opt/nodejs/node_modules/my-child-module.js", + operation_name: "aws.lambda.require_layer", + "resource.name": "myChildModule", + resource_names: "myChildModule", + service: "aws.lambda", + }); + const span4 = mockStartSpan.mock.calls[3]; + expect(span4[0]).toEqual("aws.lambda.require_core_module"); + expect(span4[1].tags).toEqual({ + filename: "http", + operation_name: "aws.lambda.require_core_module", + "resource.name": "myCoreModule", + resource_names: "myCoreModule", + service: "aws.lambda", + }); + const span5 = mockStartSpan.mock.calls[4]; + expect(span5[0]).toEqual("aws.lambda.require_runtime"); + expect(span5[1].tags).toEqual({ + filename: "/var/runtime/aws-sdk", + operation_name: "aws.lambda.require_runtime", + "resource.name": "aws-sdk", + resource_names: "aws-sdk", + service: "aws.lambda", + }); + }); + + it("optionally skips libraries", () => { + const requireNodes: RequireNode[] = [ + { + id: "handler", + filename: "/var/task/handler.js", + startTime: 1, + endTime: 6, + children: [ + { + id: "myChildModule", + filename: "/opt/nodejs/node_modules/my-child-module.js", + startTime: 2, + endTime: 3, + }, + { + id: "myCoreModule", + filename: "http", + startTime: 4, + endTime: 5, + }, + { + id: "aws-sdk", + filename: "/var/runtime/aws-sdk", + startTime: 4, + endTime: 5, + }, + ], + } as any as RequireNode, + ]; + const coldStartConfig: ColdStartTracerConfig = { + tracerWrapper: new TracerWrapper(), + parentSpan: { + span: {}, + name: "my-lambda-span", + } as any as SpanWrapper, + lambdaFunctionName: "my-function-name", + coldStartSpanFinishTime: 500, + minDuration: 1, + ignoreLibs: "myChildModule,myCoreModule", + }; + const coldStartTracer = new ColdStartTracer(coldStartConfig); + coldStartTracer.trace(requireNodes); + expect(mockStartSpan).toHaveBeenCalledTimes(3); + expect(mockFinishSpan).toHaveBeenCalledTimes(3); + const span1 = mockStartSpan.mock.calls[0]; + expect(span1[0]).toEqual("aws.lambda.load"); + expect(span1[1].tags).toEqual({ + operation_name: "aws.lambda.require", + "resource.name": "my-function-name", + resource_names: "my-function-name", + service: "aws.lambda", + }); + const span2 = mockStartSpan.mock.calls[1]; + expect(span2[0]).toEqual("aws.lambda.require"); + expect(span2[1].tags).toEqual({ + operation_name: "aws.lambda.require", + "resource.name": "handler", + resource_names: "handler", + service: "aws.lambda", + filename: "/var/task/handler.js", + }); + const span3 = mockStartSpan.mock.calls[2]; + expect(span3[0]).toEqual("aws.lambda.require_runtime"); + expect(span3[1].tags).toEqual({ + filename: "/var/runtime/aws-sdk", + operation_name: "aws.lambda.require_runtime", + "resource.name": "aws-sdk", + resource_names: "aws-sdk", + service: "aws.lambda", + }); + }); +}); diff --git a/src/trace/cold-start-tracer.ts b/src/trace/cold-start-tracer.ts new file mode 100644 index 00000000..ecfa0d4a --- /dev/null +++ b/src/trace/cold-start-tracer.ts @@ -0,0 +1,102 @@ +import { RequireNode } from "../runtime/require-tracer"; +import { SpanWrapper } from "./span-wrapper"; +import { TracerWrapper, SpanOptions } from "./tracer-wrapper"; + +export interface ColdStartTracerConfig { + tracerWrapper: TracerWrapper; + parentSpan?: SpanWrapper; + lambdaFunctionName?: string; + coldStartSpanFinishTime: number; // Equivalent to the Lambda Span Start Time + minDuration: number; + ignoreLibs: string; +} + +export class ColdStartTracer { + private tracerWrapper: TracerWrapper; + private parentSpan?: SpanWrapper; + private lambdaFunctionName?: string; + private coldStartSpanFinishTime: number; + private minDuration: number; + private ignoreLibs: string[]; + + constructor(coldStartTracerConfig: ColdStartTracerConfig) { + this.tracerWrapper = coldStartTracerConfig.tracerWrapper; + this.parentSpan = coldStartTracerConfig.parentSpan; + this.lambdaFunctionName = coldStartTracerConfig.lambdaFunctionName; + this.coldStartSpanFinishTime = coldStartTracerConfig.coldStartSpanFinishTime; + this.minDuration = coldStartTracerConfig.minDuration; + this.ignoreLibs = coldStartTracerConfig.ignoreLibs.split(","); + } + + trace(rootNodes: RequireNode[]) { + const coldStartSpanStartTime = rootNodes[0]?.startTime; + const coldStartSpan = this.createColdStartSpan(coldStartSpanStartTime, this.parentSpan); + for (const coldStartNode of rootNodes) { + this.traceTree(coldStartNode, coldStartSpan); + } + } + + private createColdStartSpan(startTime: number, parentSpan: SpanWrapper | undefined): SpanWrapper { + const options: SpanOptions = { + tags: { + service: "aws.lambda", + operation_name: "aws.lambda.require", + resource_names: this.lambdaFunctionName, + "resource.name": this.lambdaFunctionName, + }, + startTime, + }; + if (parentSpan) { + options.childOf = parentSpan.span; + } + const newSpan = new SpanWrapper(this.tracerWrapper.startSpan("aws.lambda.load", options), {}); + newSpan.finish(this.coldStartSpanFinishTime); + return newSpan; + } + + private coldStartSpanOperationName(filename: string): string { + if (filename.startsWith("/opt/")) { + return "aws.lambda.require_layer"; + } else if (filename.startsWith("/var/runtime/")) { + return "aws.lambda.require_runtime"; + } else if (filename.includes("/")) { + return "aws.lambda.require"; + } else { + return "aws.lambda.require_core_module"; + } + } + + private traceTree(reqNode: RequireNode, parentSpan: SpanWrapper | undefined): void { + if (reqNode.endTime - reqNode.startTime < this.minDuration) { + return; + } + + if (this.ignoreLibs.includes(reqNode.id)) { + return; + } + + const options: SpanOptions = { + tags: { + service: "aws.lambda", + operation_name: this.coldStartSpanOperationName(reqNode.filename), + resource_names: reqNode.id, + "resource.name": reqNode.id, + filename: reqNode.filename, + }, + startTime: reqNode.startTime, + }; + if (parentSpan) { + options.childOf = parentSpan.span; + } + const newSpan = new SpanWrapper( + this.tracerWrapper.startSpan(this.coldStartSpanOperationName(reqNode.filename), options), + {}, + ); + newSpan?.finish(reqNode.endTime); + if (reqNode.endTime - reqNode.startTime > this.minDuration) { + for (const node of reqNode.children || []) { + this.traceTree(node, newSpan); + } + } + } +} diff --git a/src/trace/listener.spec.ts b/src/trace/listener.spec.ts index b6f30cc1..4f89f2ac 100644 --- a/src/trace/listener.spec.ts +++ b/src/trace/listener.spec.ts @@ -81,6 +81,8 @@ describe("TraceListener", () => { decodeAuthorizerContext: true, mergeDatadogXrayTraces: false, injectLogContext: false, + minColdStartTraceDuration: 3, + coldStartTraceSkipLib: "", }; const context = { invokedFunctionArn: "arn:aws:lambda:us-east-1:123456789101:function:my-lambda", diff --git a/src/trace/listener.ts b/src/trace/listener.ts index a335e181..262cc728 100644 --- a/src/trace/listener.ts +++ b/src/trace/listener.ts @@ -8,7 +8,8 @@ import { } from "./context"; import { patchHttp, unpatchHttp } from "./patch-http"; import { TraceContextService } from "./trace-context-service"; -import { extractTriggerTags, extractHTTPStatusCodeTag, eventSubTypes, parseEventSourceSubType } from "./trigger"; +import { extractTriggerTags, extractHTTPStatusCodeTag } from "./trigger"; +import { ColdStartTracerConfig, ColdStartTracer } from "./cold-start-tracer"; import { logDebug, tagObject } from "../utils"; import { didFunctionColdStart } from "../utils/cold-start"; @@ -18,6 +19,7 @@ import { patchConsole } from "./patch-console"; import { SpanContext, TraceOptions, TracerWrapper } from "./tracer-wrapper"; import { SpanInferrer } from "./span-inferrer"; import { SpanWrapper } from "./span-wrapper"; +import { getTraceTree } from "../runtime/index"; export type TraceExtractor = (event: any, context: Context) => TraceContext; export interface TraceConfig { @@ -55,6 +57,14 @@ export interface TraceConfig { * Custom trace extractor function */ traceExtractor?: TraceExtractor; + /** + * Minimum duration dependency to trace + */ + minColdStartTraceDuration: number; + /** + * Libraries to ignore from cold start traces + */ + coldStartTraceSkipLib: string; } export class TraceListener { @@ -120,6 +130,7 @@ export class TraceListener { this.config.encodeAuthorizerContext, ); } + this.lambdaSpanParentContext = this.inferredSpan?.span || parentSpanContext; this.context = context; this.triggerTags = extractTriggerTags(event, context); @@ -145,7 +156,19 @@ export class TraceListener { tagObject(this.tracerWrapper.currentSpan, "function.request", event); tagObject(this.tracerWrapper.currentSpan, "function.response", result); } - + const coldStartNodes = getTraceTree(); + if (coldStartNodes.length > 0 && didFunctionColdStart()) { + const coldStartConfig: ColdStartTracerConfig = { + tracerWrapper: this.tracerWrapper, + coldStartSpanFinishTime: this.wrappedCurrentSpan?.startTime(), + parentSpan: this.inferredSpan || this.wrappedCurrentSpan, + lambdaFunctionName: this.context?.functionName, + minDuration: this.config.minColdStartTraceDuration, + ignoreLibs: this.config.coldStartTraceSkipLib, + }; + const coldStartTracer = new ColdStartTracer(coldStartConfig); + coldStartTracer.trace(coldStartNodes); + } if (this.triggerTags) { const statusCode = extractHTTPStatusCodeTag(this.triggerTags, result);