├── .babelrc ├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request.md └── workflows │ ├── push-actions.yml │ ├── send-pr-details-on-close.yml │ ├── verify-pr-details.yml │ └── version-testing.yml ├── .gitignore ├── .npmignore ├── .nvmrc ├── .prettierrc ├── CONTRIBUTING.md ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── jest.instrumentations.config.js ├── jest.instrumentations.setup.js ├── jest.unit.config.js ├── jest.unit.setup.js ├── jsconfig.json ├── package-lock.json ├── package.json ├── requirements-ci.txt ├── scripts ├── bd_to_prod.sh ├── checks.sh ├── ci_deploy.sh ├── delete_old_version_testing_branches.sh ├── deploy.sh ├── describe_supported_versions_diff.sh ├── gather_version_artifacts.py ├── init_tested_versions.sh ├── remove.sh ├── test_untested_versions.js ├── tested-versions-file-utils.js ├── tested_versions_utils.py ├── update_dist_version.sh └── update_supported_packages_documentation.py ├── src ├── bootstrap.ts ├── constants.ts ├── dependencies │ ├── index.ts │ └── report.ts ├── distro-sync-init.ts ├── distro.test.ts ├── distro.ts ├── exporters │ ├── FileExporter.ts │ ├── FileLogExporter.test.ts │ ├── FileLogExporter.ts │ ├── FileSpanExporter.test.ts │ ├── FileSpanExporter.ts │ └── index.ts ├── instrumentations │ ├── @aws-sdk │ │ └── client-sqs │ │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── @aws-sdk │ │ │ │ └── client-sqs │ │ │ ├── 16 │ │ │ └── @aws-sdk │ │ │ │ └── client-sqs │ │ │ ├── 18 │ │ │ └── @aws-sdk │ │ │ │ └── client-sqs │ │ │ └── 20 │ │ │ └── @aws-sdk │ │ │ └── client-sqs │ ├── @grpc │ │ └── grpc-js │ │ │ ├── GrpcInstrumentation.ts │ │ │ ├── grpcInstrumentation.test.js │ │ │ ├── tested_versions │ │ │ ├── 14 │ │ │ │ └── @grpc │ │ │ │ │ └── grpc-js │ │ │ ├── 16 │ │ │ │ └── @grpc │ │ │ │ │ └── grpc-js │ │ │ ├── 18 │ │ │ │ └── @grpc │ │ │ │ │ └── grpc-js │ │ │ └── 20 │ │ │ │ └── @grpc │ │ │ │ └── grpc-js │ │ │ ├── utils.test.js │ │ │ ├── utils.ts │ │ │ ├── wrapGrpcClient.ts │ │ │ └── wrapGrpcServer.ts │ ├── @nestjs │ │ └── core │ │ │ ├── NestInstrumentation.ts │ │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── @nestjs │ │ │ │ └── core │ │ │ ├── 16 │ │ │ └── @nestjs │ │ │ │ └── core │ │ │ ├── 18 │ │ │ └── @nestjs │ │ │ │ └── core │ │ │ └── 20 │ │ │ └── @nestjs │ │ │ └── core │ ├── amqplib │ │ ├── AmqplibInstrumentation.test.js │ │ ├── AmqplibInstrumentation.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── amqplib │ │ │ ├── 16 │ │ │ └── amqplib │ │ │ ├── 18 │ │ │ └── amqplib │ │ │ └── 20 │ │ │ └── amqplib │ ├── aws-sdk │ │ ├── LumigoAwsSdkLibInstrumentation.ts │ │ ├── LumigoAwsSdkV2LibInstrumentation.ts │ │ ├── LumigoAwsSdkV3LibInstrumentation.ts │ │ ├── attribute-extractors.test.ts │ │ ├── attribute-extractors.ts │ │ ├── hooks.test.ts │ │ ├── hooks.ts │ │ ├── index.ts │ │ ├── shared.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── aws-sdk │ │ │ ├── 16 │ │ │ └── aws-sdk │ │ │ ├── 18 │ │ │ └── aws-sdk │ │ │ └── 20 │ │ │ └── aws-sdk │ ├── bunyan │ │ ├── BunyanInstrumentation.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── bunyan │ │ │ ├── 16 │ │ │ └── bunyan │ │ │ ├── 18 │ │ │ └── bunyan │ │ │ └── 20 │ │ │ └── bunyan │ ├── express │ │ ├── ExpressInstrumentation.ts │ │ ├── express.ts │ │ ├── expressInstrumentation.test.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── express │ │ │ ├── 16 │ │ │ └── express │ │ │ ├── 18 │ │ │ └── express │ │ │ └── 20 │ │ │ └── express │ ├── fastify │ │ ├── FastifyInstrumentation.ts │ │ ├── fastifyInstrumentation.test.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── fastify │ │ │ ├── 16 │ │ │ └── fastify │ │ │ ├── 18 │ │ │ └── fastify │ │ │ └── 20 │ │ │ └── fastify │ ├── hooksIfc.ts │ ├── https │ │ ├── HttpInstrumentation.ts │ │ ├── http.test.js │ │ ├── http.ts │ │ └── httpInstrumentation.test.ts │ ├── instrumentor.ts │ ├── ioredis │ │ ├── IORedisInstrumentation.test.js │ │ ├── IORedisInstrumentation.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── ioredis │ │ │ ├── 16 │ │ │ └── ioredis │ │ │ ├── 18 │ │ │ └── ioredis │ │ │ └── 20 │ │ │ └── ioredis │ ├── kafkajs │ │ ├── KafkaJsInstrumentation.test.js │ │ ├── KafkaJsInstrumentation.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── kafkajs │ │ │ ├── 16 │ │ │ └── kafkajs │ │ │ ├── 18 │ │ │ └── kafkajs │ │ │ └── 20 │ │ │ └── kafkajs │ ├── logsInstrumentation.ts │ ├── mongodb │ │ ├── MongoDBInstrumentation.ts │ │ ├── mongoDBInstrumentation.test.js │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── mongodb │ │ │ ├── 16 │ │ │ └── mongodb │ │ │ ├── 18 │ │ │ └── mongodb │ │ │ └── 20 │ │ │ └── mongodb │ ├── next │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── next │ │ │ ├── 16 │ │ │ └── next │ │ │ ├── 18 │ │ │ └── next │ │ │ └── 20 │ │ │ └── next │ ├── pg │ │ ├── PgInstrumentation.test.js │ │ ├── PgInstrumentation.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── pg │ │ │ ├── 16 │ │ │ └── pg │ │ │ ├── 18 │ │ │ └── pg │ │ │ └── 20 │ │ │ └── pg │ ├── pino │ │ ├── PinoInstrumentation.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── pino │ │ │ ├── 16 │ │ │ └── pino │ │ │ ├── 18 │ │ │ └── pino │ │ │ └── 20 │ │ │ └── pino │ ├── prisma │ │ ├── PrismaInstrumentation.test.js │ │ ├── PrismaInstrumentation.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── prisma │ │ │ ├── 16 │ │ │ └── prisma │ │ │ ├── 18 │ │ │ └── prisma │ │ │ └── 20 │ │ │ └── prisma │ ├── redis │ │ ├── RedisInstrumentation.test.js │ │ ├── RedisInstrumentation.ts │ │ └── tested_versions │ │ │ ├── 14 │ │ │ └── redis │ │ │ ├── 16 │ │ │ └── redis │ │ │ ├── 18 │ │ │ └── redis │ │ │ └── 20 │ │ │ └── redis │ └── winston │ │ ├── WinstonInstrumentation.ts │ │ └── tested_versions │ │ ├── 14 │ │ └── winston │ │ ├── 16 │ │ └── winston │ │ ├── 18 │ │ └── winston │ │ └── 20 │ │ └── winston ├── logging.ts ├── parsers │ ├── aws.test.js │ └── aws.ts ├── processors │ ├── LumigoLogRecordProcessor.test.ts │ └── LumigoLogRecordProcessor.ts ├── propagator │ └── w3cTraceContextPropagator.ts ├── requireUtils.test.ts ├── requireUtils.ts ├── resources │ ├── detectors │ │ ├── LumigoContainerNameDetector.test.ts │ │ ├── LumigoContainerNameDetector.ts │ │ ├── LumigoDistroDetector.test.ts │ │ ├── LumigoDistroDetector.ts │ │ ├── LumigoKubernetesDetector.test.ts │ │ ├── LumigoKubernetesDetector.ts │ │ ├── LumigoTagDetector.test.ts │ │ ├── LumigoTagDetector.ts │ │ ├── ProcessEnvironmentDetector.test.ts │ │ ├── ProcessEnvironmentDetector.ts │ │ └── index.ts │ ├── spanProcesser.test.js │ └── spanProcessor.ts ├── samplers │ ├── combinedSampler.test.ts │ ├── combinedSampler.ts │ ├── lumigoSampler.test.js │ ├── lumigoSampler.ts │ ├── mongodbSampler.test.ts │ ├── mongodbSampler.ts │ ├── redisSampler.test.ts │ └── redisSampler.ts ├── spans │ ├── awsSpan.test.ts │ ├── awsSpan.ts │ └── types.ts ├── supportedVersions.json ├── test │ └── integration │ │ ├── @grpc │ │ └── tested_versions │ │ ├── @nestjs │ │ └── tested_versions │ │ ├── amqplib │ │ └── tested_versions │ │ ├── express │ │ └── tested_versions │ │ ├── fastify │ │ └── tested_versions │ │ ├── ioredis │ │ └── tested_versions │ │ ├── kafkajs │ │ └── tested_versions │ │ ├── mongodb │ │ └── tested_versions │ │ ├── next │ │ └── tested_versions │ │ ├── pg │ │ └── tested_versions │ │ ├── prisma │ │ └── tested_versions │ │ └── redis │ │ └── tested_versions ├── tools │ ├── httpUtils.js │ ├── httpUtils.test.js │ ├── jsonSortify.test.ts │ ├── jsonSortify.ts │ ├── payloads.test.ts │ ├── payloads.ts │ ├── xmlToJson.test.js │ └── xmlToJson.ts ├── utils.test.ts └── utils.ts ├── test ├── fixtures │ └── dummy-module │ │ └── index.js ├── helpers │ └── InstrumentationsVersionManager.ts ├── instrumentations │ ├── @aws-sdk │ │ └── client-sqs │ │ │ ├── .gitignore │ │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── aws-sdk-client-sqs-app.js │ │ │ └── package.json │ │ │ └── aws-sdk-v3.test.ts │ ├── amqplib │ │ ├── .gitignore │ │ ├── amqplib.test.ts │ │ ├── amqplibTestUtils.js │ │ └── app │ │ │ ├── .gitignore │ │ │ ├── amqplib_app.js │ │ │ └── package.json │ ├── aws-sdk │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── aws-sdk-app.js │ │ │ └── package.json │ │ └── aws-sdk-v2.test.ts │ ├── bunyan │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── bunyan_app.js │ │ │ └── package.json │ │ └── bunyan.test.ts │ ├── express │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── express_app.js │ │ │ └── package.json │ │ └── express.test.ts │ ├── fastify │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── fastify_app.js │ │ │ └── package.json │ │ └── fastify.test.ts │ ├── features │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── app.js │ │ │ ├── app.ts │ │ │ ├── package.json │ │ │ └── tsconfig.json │ │ ├── features.test.ts │ │ └── require-precedence │ │ │ ├── app-with-distro-dep │ │ │ ├── app.js │ │ │ └── package.json │ │ │ ├── app-with-logger-and-distro-deps │ │ │ ├── app.js │ │ │ └── package.json │ │ │ ├── app-with-logger-dep │ │ │ ├── app.js │ │ │ └── package.json │ │ │ ├── distro-only │ │ │ └── package.json │ │ │ └── logger-only │ │ │ └── package.json │ ├── grpc-js │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── greeter_client.js │ │ │ ├── greeter_server.js │ │ │ ├── grpc_app.js │ │ │ ├── helloworld.proto │ │ │ └── package.json │ │ └── grpc-js.test.ts │ ├── http │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── http_app.js │ │ │ └── package.json │ │ ├── http.test.ts │ │ └── test-resources │ │ │ └── large-response.json │ ├── ioredis │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── ioredis_app.js │ │ │ └── package.json │ │ ├── ioredis.test.ts │ │ └── ioredisTestUtils.ts │ ├── kafkajs │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── kafkajs_app.js │ │ │ └── package.json │ │ ├── kafkaJsTestUtils.js │ │ └── kafkajs.test.ts │ ├── mongodb │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── dbUtils.js │ │ │ ├── mongodb_app.js │ │ │ └── package.json │ │ ├── mongodb.test.ts │ │ └── mongodbTestUtils.js │ ├── nestjs │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .eslintrc.js │ │ │ ├── .gitignore │ │ │ ├── .prettierrc │ │ │ ├── README.md │ │ │ ├── nest-cli.json │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── app.controller.spec.ts │ │ │ │ ├── app.controller.ts │ │ │ │ ├── app.module.ts │ │ │ │ ├── app.service.ts │ │ │ │ └── main.ts │ │ │ ├── tsconfig.build.json │ │ │ └── tsconfig.json │ │ └── nestjs.test.ts │ ├── next │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── next.config.mjs │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── postcss.config.mjs │ │ │ ├── server.mjs │ │ │ ├── src │ │ │ │ ├── app │ │ │ │ │ ├── globals.css │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── quit │ │ │ │ │ │ └── page.tsx │ │ │ │ └── pages │ │ │ │ │ └── .keepme │ │ │ ├── tailwind.config.ts │ │ │ └── tsconfig.json │ │ └── next.test.ts │ ├── pg │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── package.json │ │ │ └── postgres_app.js │ │ └── postgres.test.ts │ ├── pino │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── package.json │ │ │ └── pino_app.js │ │ └── pino.test.ts │ ├── prisma │ │ ├── .gitignore │ │ ├── app_shared_resources │ │ │ └── prisma_app.js │ │ ├── mysql_app │ │ │ ├── .gitignore │ │ │ ├── package.json │ │ │ └── prisma │ │ │ │ └── schema.prisma │ │ ├── postgres_app │ │ │ ├── .gitignore │ │ │ ├── package.json │ │ │ └── prisma │ │ │ │ └── schema.prisma │ │ ├── prisma.mysql.test.ts │ │ ├── prisma.postgres.test.ts │ │ └── prismaTestUtils.js │ ├── redis │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── package.json │ │ │ └── redis_app.js │ │ ├── redis.test.ts │ │ └── redisTestUtils.ts │ └── winston │ │ ├── .gitignore │ │ ├── app │ │ ├── .gitignore │ │ ├── package.json │ │ └── winston_app.js │ │ ├── deps │ │ └── package.json │ │ └── winston.test.ts ├── integration │ └── setup.ts └── utils │ ├── aws-sdk-helpers.ts │ ├── common.ts │ ├── fake-edge.ts │ ├── spans.ts │ ├── test-apps.ts │ ├── test-setup.ts │ ├── time.ts │ └── versions.ts ├── tsconfig.json ├── webpack.config.js └── webpack.config2.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "12" 8 | } 9 | } 10 | ], 11 | ["@babel/preset-typescript"] 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.js 2 | **/*.test.*s 3 | src/**/jsonSortify.ts 4 | src/**/xmlToJson.ts 5 | src/**/logsInstrumentation.ts -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/ban-types 2 | module.exports = { 3 | root: true, 4 | parser: '@typescript-eslint/parser', 5 | plugins: ['@typescript-eslint', 'prettier'], 6 | extends: [ 7 | 'eslint:recommended', 8 | 'plugin:@typescript-eslint/eslint-recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | 'prettier', 11 | 'plugin:import/recommended', 12 | 'plugin:import/typescript' 13 | ], 14 | rules: { 15 | '@typescript-eslint/ban-ts-comment': 'off', 16 | '@typescript-eslint/ban-ts-ignore': 'off', 17 | 'prefer-const': [ 18 | 'error', 19 | { 20 | destructuring: 'any', 21 | ignoreReadBeforeAssign: false, 22 | }, 23 | ], 24 | '@typescript-eslint/ban-types': [ 25 | 'error', 26 | { 27 | types: { 28 | String: false, 29 | Boolean: false, 30 | Number: false, 31 | Symbol: false, 32 | '{}': false, 33 | Object: false, 34 | object: false, 35 | Function: false, 36 | }, 37 | extendDefaults: true, 38 | }, 39 | ], 40 | '@typescript-eslint/no-non-null-assertion': 'off', 41 | '@typescript-eslint/no-explicit-any': 'off', 42 | '@typescript-eslint/explicit-module-boundary-types': 'off', 43 | 'no-console': 'off', 44 | 'ban-types': 'off', 45 | 'no-case-declarations': 'off', 46 | 'import/no-extraneous-dependencies': 'error' 47 | }, 48 | }; 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: doriaviram 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See an error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Runtime details** 24 | - runtime version (node8, 10x, 12).. 25 | 26 | **Screenshots** 27 | If applicable, add screenshots to help explain your problem. 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: doriaviram 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/pull_request.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Fixes Issue 4 | 5 | 6 | 7 | 8 | 9 | ## Changes proposed 10 | 11 | 12 | 13 | 14 | 18 | 19 | ## Check List (Check all the boxes which are applicable) 20 | 21 | - [ ] My code follows the code style of this project. 22 | - [ ] My change requires a change to the documentation. 23 | - [ ] I have updated the documentation accordingly. 24 | - [ ] All new and existing tests passed. 25 | - [ ] This PR does not contain plagiarized content. 26 | - [ ] The title of my pull request is a short description of the requested changes. 27 | 28 | ## Screenshots 29 | 30 | 31 | 32 | ## Note to reviewers 33 | 34 | 35 | -------------------------------------------------------------------------------- /.github/workflows/send-pr-details-on-close.yml: -------------------------------------------------------------------------------- 1 | name: Send PR close event to the environment manager 2 | 3 | on: 4 | pull_request: 5 | types: [closed] 6 | 7 | jobs: 8 | send-pr-close-event-to-env-manager: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Send PR Close Event To Env Manager 12 | run: | 13 | full_repository_name="${{github.repository}}" 14 | # the repository name is everything after the slash "lumigo-io/" in the full repository name 15 | repository_name="${full_repository_name#lumigo-io/}" 16 | 17 | source_branch_name="${{github.head_ref}}" 18 | 19 | is_merged="${{github.event.pull_request.merged}}" 20 | if [ "$is_merged" = "true" ]; then 21 | event="PR_MERGED" 22 | else 23 | event="PR_CLOSED" 24 | fi 25 | 26 | request_type="POST" 27 | route="v1/github_actions_trigger" 28 | 29 | body="{" 30 | body+=" \"event\": \"${event}\"" 31 | body+=" , \"repository_name\": \"${repository_name}\"" 32 | body+=" , \"source_branch_name\": \"${source_branch_name}\"" 33 | body+="}" 34 | 35 | params=(\ 36 | -s \ 37 | --header "x-api-key: ${{secrets.ENV_MANAGER_API_KEY}}" \ 38 | --header "Content-Type: application/json" \ 39 | --compressed \ 40 | --request "$request_type" \ 41 | --data "$body") 42 | 43 | # ENV_MANAGER_API_ROOT="https://XXXX.execute-api.us-west-2.amazonaws.com/prod/env-manager/v1" 44 | params+=("${{secrets.ENV_MANAGER_API_ROOT}}/${route}") 45 | curl "${params[@]}" | tr -d '\r' 46 | -------------------------------------------------------------------------------- /.github/workflows/verify-pr-details.yml: -------------------------------------------------------------------------------- 1 | name: Check PR title format 2 | 3 | on: 4 | pull_request: 5 | types: 6 | # Everytime a PR is opened, reopened 7 | - opened 8 | - reopened 9 | # Everytime a PR is edited (for example: changing the title) 10 | - edited 11 | # Everytime the PR head branch is updated (for example after pushing a new commit) 12 | - synchronize 13 | 14 | jobs: 15 | # Job that checks the title of the PR & makes sure it fits the semantic versioning format 16 | check-pr-title: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Check PR Title Format 20 | uses: amannn/action-semantic-pull-request@v5 21 | if: github.event_name == 'pull_request' 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | with: 25 | disallowScopes: | 26 | release 27 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !dist/**/**.json 3 | !dist/**/**.js 4 | !dist/**/**.js.map 5 | !dist/**/**.ts 6 | !dist/**/**.d.ts 7 | !package.json 8 | !README.md 9 | !LICENSE 10 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.20.2 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "trailingComma": "es5", 7 | "useTabs": false, 8 | "parser": "babel", 9 | "overrides": [ 10 | { 11 | "files": "*.json", 12 | "options": { "parser": "json", "printWidth": 200 } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | attrs = "==21.4.0" 8 | 9 | [dev-packages] 10 | 11 | [requires] 12 | python_version = "3.9" 13 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "e98338fe3176b9e2d6c544fa7cf337a3ff571f342b9efbf0868b25bfbbf95da8" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.9" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "attrs": { 20 | "hashes": [ 21 | "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", 22 | "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" 23 | ], 24 | "index": "pypi", 25 | "version": "==21.4.0" 26 | } 27 | }, 28 | "develop": {} 29 | } 30 | -------------------------------------------------------------------------------- /jest.instrumentations.config.js: -------------------------------------------------------------------------------- 1 | const allInstrumentations = '**'; 2 | const instrumentationToTest = process.env.INSTRUMENTATION_UNDER_TEST || allInstrumentations; 3 | 4 | /** @type {import('jest').Config} */ 5 | const config = { 6 | testEnvironment: 'node', 7 | testMatch: [`**/instrumentations/${instrumentationToTest}/**/*.test.ts`], 8 | roots: ['./test'], 9 | setupFilesAfterEnv: ['./jest.instrumentations.setup.js', 'jest-json', 'jest-expect-message', 'jest-extended/all'], 10 | reporters: ['default', 'jest-summarizing-reporter'], 11 | }; 12 | 13 | module.exports = config; 14 | -------------------------------------------------------------------------------- /jest.instrumentations.setup.js: -------------------------------------------------------------------------------- 1 | require('jest-json'); 2 | require('jest-chain'); 3 | const { instrumentationsVersionManager } = require('./test/helpers/InstrumentationsVersionManager'); 4 | const fs = require('fs'); 5 | const { 6 | compareVersions, 7 | loadPackageVersionsFromBackup, 8 | } = require('./scripts/tested-versions-file-utils'); 9 | 10 | const runtimeVersion = parseInt(process.version.slice(1).split('.')[0]); 11 | const oldEnv = Object.assign({}, process.env); 12 | beforeEach(() => { 13 | process.env = { ...oldEnv }; 14 | }); 15 | 16 | afterEach(() => { 17 | process.env = { ...oldEnv }; 18 | }); 19 | 20 | beforeAll(() => { 21 | global.console = require('console'); 22 | require('console-stamp')(global.console); 23 | }); 24 | 25 | afterAll(() => { 26 | console.info('Starting afterAll...'); 27 | 28 | if (process.env.DISABLE_SUPPORTED_VERSIONS_UPDATE?.toLowerCase() === 'true') { 29 | console.info('DISABLE_SUPPORTED_VERSIONS_UPDATE is set to true, skipping post-test update.'); 30 | } else { 31 | const versions = instrumentationsVersionManager.getInstrumentationsVersions(); 32 | console.info('Adding tested versions', JSON.stringify(versions)); 33 | const versions_keys = Object.keys(versions); 34 | if (versions_keys.length) { 35 | versions_keys.forEach((pkg) => { 36 | // updated supported versions file 37 | const testedVersionFolder = `./src/instrumentations/${pkg}/tested_versions`; 38 | const testVersionsFile = `${testedVersionFolder}/${runtimeVersion}/${pkg}`; 39 | fs.mkdirSync(testedVersionFolder, { recursive: true }); 40 | const versionStrings = versions[pkg].unsupported 41 | .map((v) => `!${v}`) 42 | .concat(versions[pkg].supported) 43 | .concat(loadPackageVersionsFromBackup(pkg)) 44 | .sort(compareVersions) 45 | .join('\n'); 46 | fs.writeFileSync(testVersionsFile, versionStrings); 47 | console.info('Finish afterAll, supported version files were updated.'); 48 | }); 49 | } else { 50 | console.info('Finish afterAll, no versions to update.'); 51 | } 52 | } 53 | }); 54 | -------------------------------------------------------------------------------- /jest.unit.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | testMatch: ['**/**/*.test.ts', '**/**/*.test.js'], 4 | roots: ['./src'], 5 | coverageDirectory: './coverage/', 6 | collectCoverage: true, 7 | collectCoverageFrom: [ 8 | '**/src/**/**/**/**.js', 9 | '**/src/**/**/**/**.ts', 10 | '!./src/tools/xmlToJson.ts', 11 | '!./src/testUtils/**/**.*', 12 | '!./src/instrumentors/logsInstrumentation.ts', 13 | ], 14 | setupFilesAfterEnv: ['./jest.unit.setup.js'], 15 | coverageThreshold: { 16 | global: { 17 | lines: 50, 18 | }, 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /jest.unit.setup.js: -------------------------------------------------------------------------------- 1 | const oldEnv = Object.assign({}, process.env); 2 | 3 | beforeEach(() => { 4 | process.env = { ...oldEnv }; 5 | }); 6 | 7 | afterEach(() => { 8 | process.env = { ...oldEnv }; 9 | }); 10 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeAcquisition": { 3 | "include": ["jest"] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /requirements-ci.txt: -------------------------------------------------------------------------------- 1 | attrs==21.4.0 -------------------------------------------------------------------------------- /scripts/bd_to_prod.sh: -------------------------------------------------------------------------------- 1 | echo "Creating new credential files" 2 | enc_location=../common-resources/encrypted_files/credentials_production.enc 3 | if [[ ! -f ${enc_location} ]] 4 | then 5 | echo "$enc_location not found" 6 | exit 1 7 | fi 8 | 9 | mkdir -p ~/.aws 10 | echo "${KEY}" | gpg --batch -d --passphrase-fd 0 ${enc_location} > ~/.aws/credentials 11 | ./scripts/deploy.sh --env prod -------------------------------------------------------------------------------- /scripts/checks.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ -n "$CIRCLECI" ]] 4 | then 5 | npm run prettier:ci 6 | else 7 | npm run prettier:fix 8 | fi 9 | -------------------------------------------------------------------------------- /scripts/ci_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | pushd "$(dirname "$0")" &> /dev/null 5 | # Go back one spot because we are on scripts dir. The other scripts assume you are in the root folder 6 | cd .. 7 | ../utils/common_bash/defaults/ci_deploy.sh opentelemetry-js-distro 8 | popd &> /dev/null -------------------------------------------------------------------------------- /scripts/delete_old_version_testing_branches.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | today=$(date +%Y%m%d) 6 | echo "Today: $today" 7 | if [ "$CI" = true ]; then 8 | unshallow_flag="--unshallow" 9 | fi 10 | git fetch $unshallow_flag --force 11 | echo "Gathering version testing branches..." 12 | version_testing_branches=$(git branch -r | grep -E '(version-testing-[0-9]{8})' || echo "") 13 | if [ -z "$version_testing_branches" ]; then 14 | echo "No version testing branches found." 15 | exit 0 16 | fi 17 | echo "Unfiltered version testing branches: $version_testing_branches" 18 | today_branches=$(echo "$version_testing_branches" | grep "$today" || echo "") 19 | if [ -z "$today_branches" ]; then 20 | echo "No version testing branch from today needs to be protected." 21 | branches_for_deletion=$version_testing_branches 22 | else 23 | if [ "$version_testing_branches" = "$today_branches" ]; then 24 | echo "Today's version testing branch is the only version testing branch, aborting..." 25 | exit 0 26 | fi 27 | echo "Today's version testing branches: $today_branches" 28 | echo "Removing today's version testing branch from the list of branches to be deleted..." 29 | branches_for_deletion=$( \ 30 | git branch -r \ 31 | | grep -E '(version-testing-[0-9]{8})' \ 32 | | grep -v "$today" \ 33 | | awk -F'/' '{print $2}' \ 34 | ) 35 | fi 36 | if [ -z "$branches_for_deletion" ]; then 37 | echo "No version testing branches need to be deleted." 38 | exit 0 39 | fi 40 | echo "Branches marked for deletion:" 41 | echo "$branches_for_deletion" 42 | echo "Removing branches..." 43 | echo "$branches_for_deletion" | xargs -I {} git push origin --delete {} 44 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | setup_git() { 5 | git config --global user.email "no-reply@build.com" 6 | git config --global user.name "CircleCI" 7 | git checkout main 8 | } 9 | 10 | echo "Install a project with a clean state" 11 | npm ci 12 | 13 | echo "Setting production ad NODE_ENV" 14 | export NODE_ENV=production 15 | 16 | echo "Build tracer" 17 | npm run build 18 | cp package.json dist 19 | setup_git 20 | 21 | echo "Publish to NPM" 22 | echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc 23 | echo "Running semantic-release" 24 | 25 | # merge stderr and stdout so we can examine the logs if the command fails logically but doesn't return a non-zero exit code 26 | npm run semantic-release 2>&1 | tee semantic_release_logs.txt 27 | 28 | if grep -q "npm ERR! Exit status" semantic_release_logs.txt; then 29 | echo "semantic-release failed, see details above" 30 | exit 1 31 | fi 32 | 33 | if grep -q "no new version is released" semantic_release_logs.txt; then 34 | echo "Marking deployment as failed, as no new version would be released." 35 | exit 1 36 | fi 37 | 38 | echo "Pushing to origin/main" 39 | git push origin main 40 | 41 | echo "Pushing binary to logz" 42 | source ../utils/common_bash/functions.sh 43 | send_metric_to_logz_io type=\"Release\" 44 | -------------------------------------------------------------------------------- /scripts/describe_supported_versions_diff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | readonly SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )"; 6 | readonly ROOT_DIR="$(dirname ${SCRIPT_DIR})" 7 | 8 | echo "feat: Test additional package versions [auto-test-update]" 9 | 10 | git diff --name-only -- "${ROOT_DIR}/src/" | \ 11 | sort | \ 12 | while read -r modified_version_file; do \ 13 | package_name=$(basename "${modified_version_file}") 14 | runtime_path=$(dirname "${modified_version_file}") 15 | runtime=$(basename "${runtime_path}") 16 | new_versions=$(git diff HEAD --no-ext-diff --unified=0 --exit-code -a --no-prefix -- ${modified_version_file} | egrep "^\+" | tail -n +2 | sed 's/\+\(.*\)/\1/' | tr '\n' ' ') 17 | echo "${package_name} (${runtime}): ${new_versions}" 18 | done 19 | -------------------------------------------------------------------------------- /scripts/init_tested_versions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PACKAGE_NAME="$1" 4 | SUPPORTED_VERSIONS=(14 16 18 20) 5 | 6 | if [ -z "$PACKAGE_NAME" ]; then 7 | echo "Usage: $0 " 8 | exit 1 9 | fi 10 | 11 | base_folder="src/instrumentations/${PACKAGE_NAME}/tested_versions" 12 | test_folder="src/test/integration/${PACKAGE_NAME}" 13 | 14 | echo "Creating tested versions folders under ${base_folder}..." 15 | for version in "${SUPPORTED_VERSIONS[@]}"; do 16 | echo "Creating ${version} folder..." 17 | version_folder="${base_folder}/${version}" 18 | mkdir -p "$version_folder" 19 | touch "${version_folder}/${PACKAGE_NAME}" 20 | done 21 | 22 | echo "" 23 | echo "Creating tested versions symlink in ${test_folder}..." 24 | mkdir -p "$test_folder" 25 | pushd "$test_folder" 26 | if [ -e tested_versions ]; then 27 | echo "Removing old tested_versions symlink..." 28 | rm tested_versions 29 | fi 30 | echo "linking from ${test_folder} to ${base_folder}..." 31 | ln -s ../../../../${base_folder} tested_versions 32 | popd 33 | 34 | echo "" 35 | echo "Done" 36 | -------------------------------------------------------------------------------- /scripts/remove.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | pushd "$(dirname "$0")" &> /dev/null 5 | # Go back one spot because we are on scripts dir. The other scripts assume you are in the root folder 6 | cd .. 7 | ../utils/common_bash/defaults/remove.sh "lumigo-tracer-extension" $* 8 | popd &> /dev/null 9 | -------------------------------------------------------------------------------- /scripts/tested-versions-file-utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const semver = require('semver'); 3 | 4 | const compareVersions = (v1, v2) => semver.compare(v1.replace('!', ''), v2.replace('!', '')); 5 | 6 | const getBackupFileName = (pkg) => { 7 | return `${getFileName(pkg)}.backup`; 8 | }; 9 | 10 | const getFileName = (pkg) => { 11 | const runtimeVersion = parseInt(process.version.slice(1).split('.')[0]); 12 | return `src/instrumentations/${pkg}/tested_versions/${runtimeVersion}/${pkg}`; 13 | }; 14 | 15 | const backupPackageVersions = function (pkg) { 16 | const versionsFile = getFileName(pkg); 17 | if (!fs.existsSync(versionsFile)) { 18 | return; 19 | } 20 | fs.copyFileSync(versionsFile, getBackupFileName(pkg)); 21 | }; 22 | 23 | const deleteBackupPackageVersions = function (pkg) { 24 | fs.unlinkSync(getBackupFileName(pkg)); 25 | }; 26 | 27 | const loadPackageVersions = function (pkg, versionsFile) { 28 | versionsFile = versionsFile || getFileName(pkg); 29 | if (!fs.existsSync(versionsFile)) { 30 | return []; 31 | } 32 | return fs 33 | .readFileSync(versionsFile, 'utf8') 34 | .split('\n') 35 | .map((line) => line.trim()) 36 | .filter((line) => line.match(/^\d+\.\d+\.\d+$/)) 37 | .filter((line) => line.length > 0) 38 | .sort(compareVersions); 39 | }; 40 | 41 | const loadPackageVersionsFromBackup = function (pkg) { 42 | return loadPackageVersions(pkg, getBackupFileName(pkg)); 43 | }; 44 | 45 | const restorePackageVersionsFromBackup = function (pkg) { 46 | const backupVersionsFile = getBackupFileName(pkg); 47 | if (!fs.existsSync(backupVersionsFile)) { 48 | return; 49 | } 50 | fs.copyFileSync(backupVersionsFile, getFileName(pkg)); 51 | fs.unlinkSync(backupVersionsFile); 52 | }; 53 | 54 | // export the functions 55 | module.exports = { 56 | backupPackageVersions, 57 | compareVersions, 58 | deleteBackupPackageVersions, 59 | loadPackageVersions, 60 | loadPackageVersionsFromBackup, 61 | restorePackageVersionsFromBackup, 62 | }; 63 | -------------------------------------------------------------------------------- /scripts/update_dist_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | next_version=$1 4 | 5 | pushd ./dist 6 | if [ ! -f "package.json" ]; then 7 | echo "No dist/package.json found, failing deployment!" 8 | exit 1 9 | fi 10 | 11 | jq ".version = \"$next_version\"" package.json > package.tmp.json && mv package.tmp.json package.json 12 | popd -------------------------------------------------------------------------------- /scripts/update_supported_packages_documentation.py: -------------------------------------------------------------------------------- 1 | import os 2 | from tested_versions_utils import generate_support_matrix_markdown 3 | 4 | project_root = os.path.dirname(os.path.dirname(__file__)) 5 | 6 | readme_content = [] 7 | with (open(os.path.join(project_root, "README.md"), "r")) as readme: 8 | readme_content = readme.readlines() 9 | 10 | # Find the beginning of the "Supported packages" section 11 | supported_packages_start_index = readme_content.index("## Supported packages\n") 12 | next_section_start_index = None 13 | 14 | for count, line in enumerate( 15 | readme_content[supported_packages_start_index + 2 :] # noqa: E203 16 | ): 17 | if line.startswith("### "): 18 | next_section_start_index = supported_packages_start_index + 2 + count 19 | break 20 | 21 | if not next_section_start_index: 22 | raise Exception("No section found after 'Supported packages'!") 23 | 24 | updated_readme_content = readme_content[: supported_packages_start_index + 1] 25 | updated_readme_content += ["\n"] 26 | updated_readme_content += [ 27 | line + "\n" for line in generate_support_matrix_markdown( 28 | os.path.join(project_root, "src/instrumentations"), 29 | "https://www.npmjs.com/package/{}" 30 | ) 31 | ] 32 | updated_readme_content += ["\n"] 33 | updated_readme_content += readme_content[next_section_start_index:] 34 | 35 | with (open(os.path.join(project_root, "README.md"), "w")) as readme: 36 | readme.writelines(updated_readme_content) 37 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const LUMIGO_LOGGING_NAMESPACE = '@lumigo/opentelemetry'; 2 | 3 | export const DEFAULT_LUMIGO_TRACES_ENDPOINT = 4 | 'https://ga-otlp.lumigo-tracer-edge.golumigo.com/v1/traces'; 5 | 6 | export const DEFAULT_LUMIGO_LOGS_ENDPOINT = 7 | 'https://ga-otlp.lumigo-tracer-edge.golumigo.com/v1/logs'; 8 | 9 | export const DEFAULT_DEPENDENCIES_ENDPOINT = 10 | 'https://ga-otlp.lumigo-tracer-edge.golumigo.com/v1/dependencies'; 11 | 12 | // Since tracing is on by default, we allow omitting it and consider it enabled 13 | export const TRACING_ENABLED = 14 | process.env.LUMIGO_ENABLE_TRACES === undefined || 15 | process.env.LUMIGO_ENABLE_TRACES?.toLowerCase() === 'true'; 16 | 17 | export const LOGGING_ENABLED = process.env.LUMIGO_ENABLE_LOGS?.toLowerCase() === 'true'; 18 | -------------------------------------------------------------------------------- /src/dependencies/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Lumigo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export * from './report'; 17 | -------------------------------------------------------------------------------- /src/distro-sync-init.ts: -------------------------------------------------------------------------------- 1 | import { init, LumigoSdkInitialization } from './distro'; 2 | import deasync from 'deasync'; 3 | 4 | let done = false; 5 | let lumigoSdk: LumigoSdkInitialization | undefined; 6 | 7 | init 8 | .then((initializedLumigoSdk) => { 9 | lumigoSdk = initializedLumigoSdk; 10 | }) 11 | .catch((err) => { 12 | console.error(`Lumigo JS distro synchronous bootstrap failed: ${err}`); 13 | }) 14 | .finally(() => { 15 | done = true; 16 | }); 17 | 18 | deasync.loopWhile(() => !done); 19 | 20 | /* 21 | The `export =` syntax makes sure that using the sync endpoint from both TS and JS will return the same object structure: 22 | 23 | // TS 24 | import lumigoSdk from '@lumigo/opentelemetry/sync'; 25 | 26 | // JS 27 | const lumigoSdk = require('@lumigo/opentelemetry/sync'); 28 | 29 | Using `export default lumigoSdk` would have made the JS usage look like this: 30 | 31 | // JS code generated by TS would have a `default` property for interoperability 32 | const { default: lumigoSdk } = require('@lumigo/opentelemetry/sync'); 33 | */ 34 | export = lumigoSdk; 35 | -------------------------------------------------------------------------------- /src/exporters/FileLogExporter.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Lumigo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { hrTimeToMicroseconds } from '@opentelemetry/core'; 17 | import type { ReadableLogRecord } from '@opentelemetry/sdk-logs'; 18 | import { FileExporter } from './FileExporter'; 19 | 20 | /** 21 | * This is implementation of {@link FileExporter} that prints log records to a file. 22 | * This class can be used for debug purposes. It is not advised to use this 23 | * exporter in production. 24 | */ 25 | export class FileLogExporter extends FileExporter { 26 | protected exportInfo(logRecord: ReadableLogRecord): Object { 27 | return { 28 | timestamp: hrTimeToMicroseconds(logRecord.hrTime), 29 | traceId: logRecord.spanContext?.traceId, 30 | spanId: logRecord.spanContext?.spanId, 31 | traceFlags: logRecord.spanContext?.traceFlags, 32 | severityText: logRecord.severityText, 33 | severityNumber: logRecord.severityNumber, 34 | body: logRecord.body, 35 | attributes: logRecord.attributes, 36 | }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/exporters/FileSpanExporter.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Lumigo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { hrTimeToMicroseconds } from '@opentelemetry/core'; 17 | import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'; 18 | import { FileExporter } from './FileExporter'; 19 | 20 | /** 21 | * This is implementation of {@link FileExporter} that prints spans to a file. 22 | * This class can be used for debug purposes. It is not advised to use this 23 | * exporter in production. 24 | */ 25 | export class FileSpanExporter extends FileExporter { 26 | protected exportInfo(span: ReadableSpan): Object { 27 | return { 28 | traceId: span.spanContext().traceId, 29 | parentId: span.parentSpanId, 30 | name: span.name, 31 | id: span.spanContext().spanId, 32 | kind: span.kind, 33 | timestamp: hrTimeToMicroseconds(span.startTime), 34 | duration: hrTimeToMicroseconds(span.duration), 35 | attributes: span.attributes, 36 | status: span.status, 37 | events: span.events, 38 | resource: span.resource, 39 | }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/exporters/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Lumigo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export { FileSpanExporter } from './FileSpanExporter'; 18 | export { FileLogExporter } from './FileLogExporter'; 19 | -------------------------------------------------------------------------------- /src/instrumentations/@aws-sdk/client-sqs/tested_versions/14/@aws-sdk/client-sqs: -------------------------------------------------------------------------------- 1 | 3.525.0 -------------------------------------------------------------------------------- /src/instrumentations/@aws-sdk/client-sqs/tested_versions/16/@aws-sdk/client-sqs: -------------------------------------------------------------------------------- 1 | 3.525.0 -------------------------------------------------------------------------------- /src/instrumentations/@aws-sdk/client-sqs/tested_versions/18/@aws-sdk/client-sqs: -------------------------------------------------------------------------------- 1 | 3.525.0 -------------------------------------------------------------------------------- /src/instrumentations/@aws-sdk/client-sqs/tested_versions/20/@aws-sdk/client-sqs: -------------------------------------------------------------------------------- 1 | 3.525.0 -------------------------------------------------------------------------------- /src/instrumentations/@grpc/grpc-js/GrpcInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { GrpcInstrumentation } from '@opentelemetry/instrumentation-grpc'; 2 | import { TracingInstrumentor } from '../../instrumentor'; 3 | import { wrapServer } from './wrapGrpcServer'; 4 | import { wrapClient } from './wrapGrpcClient'; 5 | 6 | export default class LumigoGrpcInstrumentation extends TracingInstrumentor { 7 | getInstrumentedModule(): string { 8 | return '@grpc/grpc-js'; 9 | } 10 | 11 | getInstrumentation(): GrpcInstrumentation { 12 | wrapClient(); 13 | wrapServer(); 14 | return new GrpcInstrumentation(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/instrumentations/@grpc/grpc-js/grpcInstrumentation.test.js: -------------------------------------------------------------------------------- 1 | import LumigoGrpcInstrumentation from './GrpcInstrumentation'; 2 | 3 | describe('LumigoGrpcInstrumentation', () => { 4 | afterEach(() => { 5 | jest.clearAllMocks(); 6 | }); 7 | 8 | let lumigoGrpcInstrumentation = new LumigoGrpcInstrumentation(); 9 | 10 | test('getInstrumentedModule should return "@grpc/grpc-js"', () => { 11 | expect(lumigoGrpcInstrumentation.getInstrumentedModule()).toEqual('@grpc/grpc-js'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/instrumentations/@grpc/grpc-js/tested_versions/14/@grpc/grpc-js: -------------------------------------------------------------------------------- 1 | 1.8.0 2 | 1.8.1 3 | 1.8.2 4 | 1.8.3 5 | 1.8.4 6 | 1.8.5 7 | 1.8.6 8 | 1.8.7 9 | 1.8.8 10 | 1.8.9 11 | 1.8.10 12 | 1.8.11 13 | 1.8.12 14 | 1.8.13 15 | 1.8.14 16 | 1.8.15 17 | 1.8.16 18 | 1.8.17 19 | 1.8.18 20 | 1.8.19 21 | 1.8.20 -------------------------------------------------------------------------------- /src/instrumentations/@grpc/grpc-js/tested_versions/16/@grpc/grpc-js: -------------------------------------------------------------------------------- 1 | 1.8.0 2 | 1.8.1 3 | 1.8.2 4 | 1.8.3 5 | 1.8.4 6 | 1.8.5 7 | 1.8.6 8 | 1.8.7 9 | 1.8.8 10 | 1.8.9 11 | 1.8.10 12 | 1.8.11 13 | 1.8.12 14 | 1.8.13 15 | 1.8.14 16 | 1.8.15 17 | 1.8.16 18 | 1.8.17 19 | 1.8.18 20 | 1.8.19 21 | 1.8.20 -------------------------------------------------------------------------------- /src/instrumentations/@grpc/grpc-js/tested_versions/18/@grpc/grpc-js: -------------------------------------------------------------------------------- 1 | 1.8.0 2 | 1.8.1 3 | 1.8.2 4 | 1.8.3 5 | 1.8.4 6 | 1.8.5 7 | 1.8.6 8 | 1.8.7 9 | 1.8.8 10 | 1.8.9 11 | 1.8.10 12 | 1.8.11 13 | 1.8.12 14 | 1.8.13 15 | 1.8.14 16 | 1.8.15 17 | 1.8.16 18 | 1.8.17 19 | 1.8.18 20 | 1.8.19 21 | 1.8.20 -------------------------------------------------------------------------------- /src/instrumentations/@grpc/grpc-js/tested_versions/20/@grpc/grpc-js: -------------------------------------------------------------------------------- 1 | 1.8.0 2 | 1.8.1 3 | 1.8.2 4 | 1.8.3 5 | 1.8.4 6 | 1.8.5 7 | 1.8.6 8 | 1.8.7 9 | 1.8.8 10 | 1.8.9 11 | 1.8.10 12 | 1.8.11 13 | 1.8.12 14 | 1.8.13 15 | 1.8.14 16 | 1.8.15 17 | 1.8.16 18 | 1.8.17 19 | 1.8.18 20 | 1.8.19 21 | 1.8.20 -------------------------------------------------------------------------------- /src/instrumentations/@grpc/grpc-js/utils.test.js: -------------------------------------------------------------------------------- 1 | import { concatenatePayload, PAYLOAD_MAX_SIZE } from './utils'; 2 | 3 | describe('gRPC utils', () => { 4 | test('concatenatePayload - happy flow', () => { 5 | const payload = concatenatePayload('BODY', 'MORE'); 6 | expect(payload).toEqual('BODYMORE'); 7 | }); 8 | 9 | test('concatenatePayload - too long', () => { 10 | const payload = concatenatePayload('0'.repeat(PAYLOAD_MAX_SIZE - 1), '1'.repeat(10)); 11 | expect(payload).toEqual('0'.repeat(PAYLOAD_MAX_SIZE - 1) + '1'); 12 | }); 13 | 14 | test('concatenatePayload - dont add new payload if the current is long enough', () => { 15 | const payload = concatenatePayload('0'.repeat(PAYLOAD_MAX_SIZE), '1'.repeat(10)); 16 | expect(payload).toEqual('0'.repeat(PAYLOAD_MAX_SIZE)); 17 | }); 18 | 19 | test('concatenatePayload - JSON stringify', () => { 20 | const payload = concatenatePayload('', { next: 'bulk' }); 21 | expect(payload).toEqual('{"next":"bulk"}'); 22 | }); 23 | 24 | test('concatenatePayload - truncate long JSONs', () => { 25 | const payload = concatenatePayload('', { next: '1'.repeat(PAYLOAD_MAX_SIZE) }); 26 | expect(payload).toContain('{"next":"111111'); 27 | expect(payload.length).toEqual(PAYLOAD_MAX_SIZE); 28 | }); 29 | 30 | test('concatenatePayload - safe execute handle exceptions with returning old value', () => { 31 | const recursive = { a: 1 }; 32 | recursive.b = recursive; 33 | const payload = concatenatePayload('before', recursive); 34 | expect(payload).toEqual('before'); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/instrumentations/@grpc/grpc-js/utils.ts: -------------------------------------------------------------------------------- 1 | import { isString, safeExecute } from '@lumigo/node-core/lib/utils'; 2 | 3 | export const PAYLOAD_MAX_SIZE = 2048; 4 | 5 | export const concatenatePayload = (aggregatedData: string, currentData: unknown): string => { 6 | return safeExecute( 7 | () => { 8 | if (aggregatedData.length >= PAYLOAD_MAX_SIZE) { 9 | return aggregatedData; 10 | } 11 | const currDataStr = isString(currentData) ? currentData : JSON.stringify(currentData); 12 | return (aggregatedData + currDataStr).substring(0, PAYLOAD_MAX_SIZE); 13 | }, 14 | 'gRPC concatenate payloads', 15 | 'WARNING', 16 | aggregatedData 17 | )(); 18 | }; 19 | -------------------------------------------------------------------------------- /src/instrumentations/@nestjs/core/NestInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { NestInstrumentation } from '@opentelemetry/instrumentation-nestjs-core'; 2 | import { TracingInstrumentor } from '../../instrumentor'; 3 | 4 | export default class LumigoNestInstrumentation extends TracingInstrumentor { 5 | override isApplicable(): boolean { 6 | return ( 7 | super.isApplicable() && 8 | process.env.LUMIGO_DISABLE_NEST_INSTRUMENTATION?.toLocaleLowerCase() !== 'true' 9 | ); 10 | } 11 | 12 | getInstrumentedModule(): string { 13 | return '@nestjs/core'; 14 | } 15 | 16 | getInstrumentation(): NestInstrumentation { 17 | return new NestInstrumentation(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/instrumentations/@nestjs/core/tested_versions/14/@nestjs/core: -------------------------------------------------------------------------------- 1 | !10.3.2 -------------------------------------------------------------------------------- /src/instrumentations/@nestjs/core/tested_versions/16/@nestjs/core: -------------------------------------------------------------------------------- 1 | 10.3.2 -------------------------------------------------------------------------------- /src/instrumentations/@nestjs/core/tested_versions/18/@nestjs/core: -------------------------------------------------------------------------------- 1 | 10.3.2 -------------------------------------------------------------------------------- /src/instrumentations/@nestjs/core/tested_versions/20/@nestjs/core: -------------------------------------------------------------------------------- 1 | 10.3.2 -------------------------------------------------------------------------------- /src/instrumentations/amqplib/AmqplibInstrumentation.test.js: -------------------------------------------------------------------------------- 1 | import LumigoAmqplibInstrumentation from './AmqplibInstrumentation'; 2 | 3 | describe('LumigoAmqplibInstrumentation', () => { 4 | afterEach(() => { 5 | jest.clearAllMocks(); 6 | }); 7 | 8 | let lumigoAmqplibInstrumentation = new LumigoAmqplibInstrumentation(); 9 | 10 | test('getInstrumentedModule should return "amqplib"', () => { 11 | expect(lumigoAmqplibInstrumentation.getInstrumentedModule()).toEqual('amqplib'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/instrumentations/amqplib/AmqplibInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { CommonUtils, ScrubContext } from '@lumigo/node-core'; 2 | import type { Span } from '@opentelemetry/api'; 3 | import { 4 | AmqplibInstrumentation, 5 | ConsumeInfo, 6 | PublishInfo, 7 | } from '@opentelemetry/instrumentation-amqplib'; 8 | import { getSpanAttributeMaxLength } from '../../utils'; 9 | import { TracingInstrumentor } from '../instrumentor'; 10 | 11 | export default class LumigoAmqplibInstrumentation extends TracingInstrumentor { 12 | getInstrumentedModule(): string { 13 | return 'amqplib'; 14 | } 15 | 16 | getInstrumentation(): AmqplibInstrumentation { 17 | return new AmqplibInstrumentation({ 18 | publishHook: (span: Span, publishInfo: PublishInfo) => { 19 | span.setAttribute( 20 | 'messaging.publish.body', 21 | CommonUtils.payloadStringify( 22 | publishInfo.content.toString(), 23 | ScrubContext.HTTP_REQUEST_QUERY, 24 | getSpanAttributeMaxLength() 25 | ) 26 | ); 27 | }, 28 | consumeHook: (span: Span, consumeInfo: ConsumeInfo) => { 29 | span.setAttribute( 30 | 'messaging.consume.body', 31 | CommonUtils.payloadStringify( 32 | consumeInfo.msg.content.toString(), 33 | ScrubContext.HTTP_RESPONSE_BODY, 34 | getSpanAttributeMaxLength() 35 | ) 36 | ); 37 | }, 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/instrumentations/amqplib/tested_versions/14/amqplib: -------------------------------------------------------------------------------- 1 | 0.9.0 2 | 0.9.1 3 | 0.10.0 4 | 0.10.1 5 | 0.10.2 6 | 0.10.3 7 | 0.10.4 8 | -------------------------------------------------------------------------------- /src/instrumentations/amqplib/tested_versions/16/amqplib: -------------------------------------------------------------------------------- 1 | 0.9.0 2 | 0.9.1 3 | 0.10.0 4 | 0.10.1 5 | 0.10.2 6 | 0.10.3 7 | 0.10.4 8 | -------------------------------------------------------------------------------- /src/instrumentations/amqplib/tested_versions/18/amqplib: -------------------------------------------------------------------------------- 1 | 0.9.0 2 | 0.9.1 3 | 0.10.0 4 | 0.10.1 5 | 0.10.2 6 | 0.10.3 7 | 0.10.4 8 | -------------------------------------------------------------------------------- /src/instrumentations/amqplib/tested_versions/20/amqplib: -------------------------------------------------------------------------------- 1 | 0.9.0 2 | 0.9.1 3 | 0.10.0 4 | 0.10.1 5 | 0.10.2 6 | 0.10.3 7 | 0.10.4 8 | -------------------------------------------------------------------------------- /src/instrumentations/aws-sdk/LumigoAwsSdkLibInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk'; 2 | import { TracingInstrumentor } from '../instrumentor'; 3 | import { preRequestHook, responseHook, sqsProcessHook } from './hooks'; 4 | 5 | export abstract class LumigoAwsSdkLibInstrumentation extends TracingInstrumentor { 6 | override isApplicable(): boolean { 7 | return ( 8 | super.isApplicable() && 9 | process.env.LUMIGO_USE_AWS_SDK_INSTRUMENTATION?.toLocaleLowerCase() === 'true' 10 | ); 11 | } 12 | 13 | getInstrumentation(): AwsInstrumentation { 14 | return new AwsInstrumentation({ 15 | responseHook, 16 | preRequestHook, 17 | sqsProcessHook, 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/instrumentations/aws-sdk/LumigoAwsSdkV2LibInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { LumigoAwsSdkLibInstrumentation } from './LumigoAwsSdkLibInstrumentation'; 2 | 3 | export class LumigoAwsSdkV2LibInstrumentation extends LumigoAwsSdkLibInstrumentation { 4 | getInstrumentedModule(): string { 5 | return 'aws-sdk'; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/instrumentations/aws-sdk/LumigoAwsSdkV3LibInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { LumigoAwsSdkLibInstrumentation } from './LumigoAwsSdkLibInstrumentation'; 2 | 3 | export class LumigoAwsSdkV3LibInstrumentation extends LumigoAwsSdkLibInstrumentation { 4 | getInstrumentedModule(): string { 5 | return '@aws-sdk/client-sqs'; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/instrumentations/aws-sdk/index.ts: -------------------------------------------------------------------------------- 1 | import { LumigoAwsSdkV2LibInstrumentation } from './LumigoAwsSdkV2LibInstrumentation'; 2 | import { LumigoAwsSdkV3LibInstrumentation } from './LumigoAwsSdkV3LibInstrumentation'; 3 | 4 | export { LumigoAwsSdkV2LibInstrumentation, LumigoAwsSdkV3LibInstrumentation }; 5 | -------------------------------------------------------------------------------- /src/instrumentations/aws-sdk/shared.ts: -------------------------------------------------------------------------------- 1 | import { AwsOtherService, AwsParsedService, SupportedAwsServices } from '../../spans/types'; 2 | 3 | export const isAwsInstrumentationSpanActive = (): boolean => 4 | process.env._LUMIGO_AWS_INSTRUMENTATION_SPAN_ACTIVE === 'true'; 5 | 6 | export const setAwsInstrumentationSpanActive = (status: boolean) => 7 | (process.env._LUMIGO_AWS_INSTRUMENTATION_SPAN_ACTIVE = status.toString()); 8 | 9 | const LUMIGO_AWS_INSTRUMENTATION_SUPPORTED_SERVICE_TYPES: SupportedAwsServices[] = [ 10 | AwsParsedService.SQS, 11 | AwsOtherService.ElasticBeanstalkSqsDaemon, 12 | ]; 13 | 14 | export const isServiceSupportedByLumigoAwsSdkInstrumentation = ( 15 | serviceType: SupportedAwsServices 16 | ): boolean => LUMIGO_AWS_INSTRUMENTATION_SUPPORTED_SERVICE_TYPES.includes(serviceType); 17 | -------------------------------------------------------------------------------- /src/instrumentations/aws-sdk/tested_versions/14/aws-sdk: -------------------------------------------------------------------------------- 1 | 2.1533.0 2 | 2.1534.0 3 | 2.1535.0 4 | 2.1536.0 5 | 2.1537.0 6 | 2.1538.0 7 | 2.1539.0 8 | 2.1540.0 9 | 2.1541.0 10 | 2.1542.0 11 | 2.1543.0 12 | 2.1544.0 13 | 2.1545.0 14 | 2.1546.0 15 | 2.1547.0 16 | 2.1548.0 17 | 2.1549.0 18 | 2.1550.0 19 | 2.1551.0 20 | 2.1552.0 21 | 2.1553.0 22 | 2.1554.0 23 | 2.1555.0 24 | 2.1556.0 25 | 2.1557.0 26 | 2.1558.0 27 | 2.1559.0 28 | 2.1560.0 29 | 2.1561.0 30 | 2.1562.0 31 | 2.1563.0 32 | 2.1564.0 33 | 2.1565.0 34 | 2.1566.0 35 | 2.1567.0 36 | 2.1568.0 37 | 2.1569.0 38 | 2.1570.0 39 | 2.1571.0 40 | 2.1572.0 41 | 2.1573.0 42 | 2.1574.0 43 | 2.1575.0 44 | 2.1576.0 45 | 2.1577.0 46 | 2.1578.0 47 | 2.1579.0 48 | 2.1580.0 49 | 2.1581.0 50 | 2.1582.0 51 | 2.1583.0 52 | 2.1584.0 53 | 2.1585.0 54 | 2.1586.0 55 | 2.1587.0 56 | 2.1588.0 57 | 2.1589.0 58 | 2.1590.0 59 | 2.1591.0 60 | 2.1592.0 61 | 2.1593.0 62 | 2.1594.0 63 | 2.1595.0 64 | 2.1596.0 65 | 2.1597.0 66 | 2.1598.0 67 | 2.1599.0 68 | 2.1600.0 69 | 2.1601.0 70 | 2.1602.0 71 | 2.1603.0 72 | 2.1604.0 73 | 2.1605.0 74 | 2.1606.0 75 | 2.1607.0 76 | 2.1608.0 77 | 2.1609.0 78 | 2.1610.0 79 | 2.1611.0 80 | 2.1612.0 81 | 2.1613.0 82 | 2.1614.0 83 | 2.1615.0 84 | 2.1616.0 85 | 2.1617.0 86 | 2.1618.0 87 | 2.1619.0 88 | 2.1620.0 89 | 2.1621.0 90 | 2.1622.0 91 | 2.1623.0 92 | 2.1624.0 93 | 2.1625.0 94 | 2.1626.0 95 | 2.1627.0 96 | 2.1628.0 97 | 2.1629.0 98 | 2.1630.0 99 | 2.1631.0 100 | 2.1632.0 101 | 2.1633.0 102 | 2.1634.0 103 | 2.1635.0 104 | 2.1636.0 105 | 2.1637.0 106 | 2.1638.0 107 | 2.1639.0 108 | 2.1640.0 109 | 2.1641.0 110 | 2.1642.0 111 | 2.1643.0 112 | 2.1644.0 113 | 2.1645.0 114 | 2.1646.0 115 | 2.1647.0 116 | 2.1648.0 117 | 2.1649.0 118 | 2.1650.0 119 | 2.1651.0 120 | 2.1652.0 121 | 2.1653.0 122 | 2.1654.0 123 | 2.1655.0 124 | 2.1656.0 125 | 2.1657.0 126 | 2.1658.0 127 | 2.1659.0 128 | 2.1660.0 129 | 2.1661.0 130 | 2.1662.0 131 | 2.1663.0 132 | 2.1664.0 133 | 2.1665.0 134 | 2.1666.0 135 | 2.1667.0 136 | 2.1668.0 137 | 2.1669.0 138 | 2.1670.0 139 | 2.1671.0 140 | 2.1672.0 141 | 2.1673.0 142 | 2.1674.0 143 | 2.1675.0 144 | 2.1676.0 145 | 2.1677.0 146 | 2.1678.0 147 | 2.1679.0 148 | 2.1680.0 149 | 2.1681.0 150 | 2.1682.0 151 | 2.1683.0 152 | 2.1684.0 153 | 2.1685.0 154 | 2.1686.0 155 | 2.1687.0 156 | 2.1688.0 157 | 2.1689.0 158 | 2.1690.0 159 | 2.1691.0 160 | -------------------------------------------------------------------------------- /src/instrumentations/aws-sdk/tested_versions/16/aws-sdk: -------------------------------------------------------------------------------- 1 | 2.1533.0 2 | 2.1534.0 3 | 2.1535.0 4 | 2.1536.0 5 | 2.1537.0 6 | 2.1538.0 7 | 2.1539.0 8 | 2.1540.0 9 | 2.1541.0 10 | 2.1542.0 11 | 2.1543.0 12 | 2.1544.0 13 | 2.1545.0 14 | 2.1546.0 15 | 2.1547.0 16 | 2.1548.0 17 | 2.1549.0 18 | 2.1550.0 19 | 2.1551.0 20 | 2.1552.0 21 | 2.1553.0 22 | 2.1554.0 23 | 2.1555.0 24 | 2.1556.0 25 | 2.1557.0 26 | 2.1558.0 27 | 2.1559.0 28 | 2.1560.0 29 | 2.1561.0 30 | 2.1562.0 31 | 2.1563.0 32 | 2.1564.0 33 | 2.1565.0 34 | 2.1566.0 35 | 2.1567.0 36 | 2.1568.0 37 | 2.1569.0 38 | 2.1570.0 39 | 2.1571.0 40 | 2.1572.0 41 | 2.1573.0 42 | 2.1574.0 43 | 2.1575.0 44 | 2.1576.0 45 | 2.1577.0 46 | 2.1578.0 47 | 2.1579.0 48 | 2.1580.0 49 | 2.1581.0 50 | 2.1582.0 51 | 2.1583.0 52 | 2.1584.0 53 | 2.1585.0 54 | 2.1586.0 55 | 2.1587.0 56 | 2.1588.0 57 | 2.1589.0 58 | 2.1590.0 59 | 2.1591.0 60 | 2.1592.0 61 | 2.1593.0 62 | 2.1594.0 63 | 2.1595.0 64 | 2.1596.0 65 | 2.1597.0 66 | 2.1598.0 67 | 2.1599.0 68 | 2.1600.0 69 | 2.1601.0 70 | 2.1602.0 71 | 2.1603.0 72 | 2.1604.0 73 | 2.1605.0 74 | 2.1606.0 75 | 2.1607.0 76 | 2.1608.0 77 | 2.1609.0 78 | 2.1610.0 79 | 2.1611.0 80 | 2.1612.0 81 | 2.1613.0 82 | 2.1614.0 83 | 2.1615.0 84 | 2.1616.0 85 | 2.1617.0 86 | 2.1618.0 87 | 2.1619.0 88 | 2.1620.0 89 | 2.1621.0 90 | 2.1622.0 91 | 2.1623.0 92 | 2.1624.0 93 | 2.1625.0 94 | 2.1626.0 95 | 2.1627.0 96 | 2.1628.0 97 | 2.1629.0 98 | 2.1630.0 99 | 2.1631.0 100 | 2.1632.0 101 | 2.1633.0 102 | 2.1634.0 103 | 2.1635.0 104 | 2.1636.0 105 | 2.1637.0 106 | 2.1638.0 107 | 2.1639.0 108 | 2.1640.0 109 | 2.1641.0 110 | 2.1642.0 111 | 2.1643.0 112 | 2.1644.0 113 | 2.1645.0 114 | 2.1646.0 115 | 2.1647.0 116 | 2.1648.0 117 | 2.1649.0 118 | 2.1650.0 119 | 2.1651.0 120 | 2.1652.0 121 | 2.1653.0 122 | 2.1654.0 123 | 2.1655.0 124 | 2.1656.0 125 | 2.1657.0 126 | 2.1658.0 127 | 2.1659.0 128 | 2.1660.0 129 | 2.1661.0 130 | 2.1662.0 131 | 2.1663.0 132 | 2.1664.0 133 | 2.1665.0 134 | 2.1666.0 135 | 2.1667.0 136 | 2.1668.0 137 | 2.1669.0 138 | 2.1670.0 139 | 2.1671.0 140 | 2.1672.0 141 | 2.1673.0 142 | 2.1674.0 143 | 2.1675.0 144 | 2.1676.0 145 | 2.1677.0 146 | 2.1678.0 147 | 2.1679.0 148 | 2.1680.0 149 | 2.1681.0 150 | 2.1682.0 151 | 2.1683.0 152 | 2.1684.0 153 | 2.1685.0 154 | 2.1686.0 155 | 2.1687.0 156 | 2.1688.0 157 | 2.1689.0 158 | 2.1690.0 159 | 2.1691.0 160 | -------------------------------------------------------------------------------- /src/instrumentations/aws-sdk/tested_versions/18/aws-sdk: -------------------------------------------------------------------------------- 1 | 2.1533.0 2 | 2.1534.0 3 | 2.1535.0 4 | 2.1536.0 5 | 2.1537.0 6 | 2.1538.0 7 | 2.1539.0 8 | 2.1540.0 9 | 2.1541.0 10 | 2.1542.0 11 | 2.1543.0 12 | 2.1544.0 13 | 2.1545.0 14 | 2.1546.0 15 | 2.1547.0 16 | 2.1548.0 17 | 2.1549.0 18 | 2.1550.0 19 | 2.1551.0 20 | 2.1552.0 21 | 2.1553.0 22 | 2.1554.0 23 | 2.1555.0 24 | 2.1556.0 25 | 2.1557.0 26 | 2.1558.0 27 | 2.1559.0 28 | 2.1560.0 29 | 2.1561.0 30 | 2.1562.0 31 | 2.1563.0 32 | 2.1564.0 33 | 2.1565.0 34 | 2.1566.0 35 | 2.1567.0 36 | 2.1568.0 37 | 2.1569.0 38 | 2.1570.0 39 | 2.1571.0 40 | 2.1572.0 41 | 2.1573.0 42 | 2.1574.0 43 | 2.1575.0 44 | 2.1576.0 45 | 2.1577.0 46 | 2.1578.0 47 | 2.1579.0 48 | 2.1580.0 49 | 2.1581.0 50 | 2.1582.0 51 | 2.1583.0 52 | 2.1584.0 53 | 2.1585.0 54 | 2.1586.0 55 | 2.1587.0 56 | 2.1588.0 57 | 2.1589.0 58 | 2.1590.0 59 | 2.1591.0 60 | 2.1592.0 61 | 2.1593.0 62 | 2.1594.0 63 | 2.1595.0 64 | 2.1596.0 65 | 2.1597.0 66 | 2.1598.0 67 | 2.1599.0 68 | 2.1600.0 69 | 2.1601.0 70 | 2.1602.0 71 | 2.1603.0 72 | 2.1604.0 73 | 2.1605.0 74 | 2.1606.0 75 | 2.1607.0 76 | 2.1608.0 77 | 2.1609.0 78 | 2.1610.0 79 | 2.1611.0 80 | 2.1612.0 81 | 2.1613.0 82 | 2.1614.0 83 | 2.1615.0 84 | 2.1616.0 85 | 2.1617.0 86 | 2.1618.0 87 | 2.1619.0 88 | 2.1620.0 89 | 2.1621.0 90 | 2.1622.0 91 | 2.1623.0 92 | 2.1624.0 93 | 2.1625.0 94 | 2.1626.0 95 | 2.1627.0 96 | 2.1628.0 97 | 2.1629.0 98 | 2.1630.0 99 | 2.1631.0 100 | 2.1632.0 101 | 2.1633.0 102 | 2.1634.0 103 | 2.1635.0 104 | 2.1636.0 105 | 2.1637.0 106 | 2.1638.0 107 | 2.1639.0 108 | 2.1640.0 109 | 2.1641.0 110 | 2.1642.0 111 | 2.1643.0 112 | 2.1644.0 113 | 2.1645.0 114 | 2.1646.0 115 | 2.1647.0 116 | 2.1648.0 117 | 2.1649.0 118 | 2.1650.0 119 | 2.1651.0 120 | 2.1652.0 121 | 2.1653.0 122 | 2.1654.0 123 | 2.1655.0 124 | 2.1656.0 125 | 2.1657.0 126 | 2.1658.0 127 | 2.1659.0 128 | 2.1660.0 129 | 2.1661.0 130 | 2.1662.0 131 | 2.1663.0 132 | 2.1664.0 133 | 2.1665.0 134 | 2.1666.0 135 | 2.1667.0 136 | 2.1668.0 137 | 2.1669.0 138 | 2.1670.0 139 | 2.1671.0 140 | 2.1672.0 141 | 2.1673.0 142 | 2.1674.0 143 | 2.1675.0 144 | 2.1676.0 145 | 2.1677.0 146 | 2.1678.0 147 | 2.1679.0 148 | 2.1680.0 149 | 2.1681.0 150 | 2.1682.0 151 | 2.1683.0 152 | 2.1684.0 153 | 2.1685.0 154 | 2.1686.0 155 | 2.1687.0 156 | 2.1688.0 157 | 2.1689.0 158 | 2.1690.0 159 | 2.1691.0 160 | -------------------------------------------------------------------------------- /src/instrumentations/aws-sdk/tested_versions/20/aws-sdk: -------------------------------------------------------------------------------- 1 | 2.1533.0 2 | 2.1534.0 3 | 2.1535.0 4 | 2.1536.0 5 | 2.1537.0 6 | 2.1538.0 7 | 2.1539.0 8 | 2.1540.0 9 | 2.1541.0 10 | 2.1542.0 11 | 2.1543.0 12 | 2.1544.0 13 | 2.1545.0 14 | 2.1546.0 15 | 2.1547.0 16 | 2.1548.0 17 | 2.1549.0 18 | 2.1550.0 19 | 2.1551.0 20 | 2.1552.0 21 | 2.1553.0 22 | 2.1554.0 23 | 2.1555.0 24 | 2.1556.0 25 | 2.1557.0 26 | 2.1558.0 27 | 2.1559.0 28 | 2.1560.0 29 | 2.1561.0 30 | 2.1562.0 31 | 2.1563.0 32 | 2.1564.0 33 | 2.1565.0 34 | 2.1566.0 35 | 2.1567.0 36 | 2.1568.0 37 | 2.1569.0 38 | 2.1570.0 39 | 2.1571.0 40 | 2.1572.0 41 | 2.1573.0 42 | 2.1574.0 43 | 2.1575.0 44 | 2.1576.0 45 | 2.1577.0 46 | 2.1578.0 47 | 2.1579.0 48 | 2.1580.0 49 | 2.1581.0 50 | 2.1582.0 51 | 2.1583.0 52 | 2.1584.0 53 | 2.1585.0 54 | 2.1586.0 55 | 2.1587.0 56 | 2.1588.0 57 | 2.1589.0 58 | 2.1590.0 59 | 2.1591.0 60 | 2.1592.0 61 | 2.1593.0 62 | 2.1594.0 63 | 2.1595.0 64 | 2.1596.0 65 | 2.1597.0 66 | 2.1598.0 67 | 2.1599.0 68 | 2.1600.0 69 | 2.1601.0 70 | 2.1602.0 71 | 2.1603.0 72 | 2.1604.0 73 | 2.1605.0 74 | 2.1606.0 75 | 2.1607.0 76 | 2.1608.0 77 | 2.1609.0 78 | 2.1610.0 79 | 2.1611.0 80 | 2.1612.0 81 | 2.1613.0 82 | 2.1614.0 83 | 2.1615.0 84 | 2.1616.0 85 | 2.1617.0 86 | 2.1618.0 87 | 2.1619.0 88 | 2.1620.0 89 | 2.1621.0 90 | 2.1622.0 91 | 2.1623.0 92 | 2.1624.0 93 | 2.1625.0 94 | 2.1626.0 95 | 2.1627.0 96 | 2.1628.0 97 | 2.1629.0 98 | 2.1630.0 99 | 2.1631.0 100 | 2.1632.0 101 | 2.1633.0 102 | 2.1634.0 103 | 2.1635.0 104 | 2.1636.0 105 | 2.1637.0 106 | 2.1638.0 107 | 2.1639.0 108 | 2.1640.0 109 | 2.1641.0 110 | 2.1642.0 111 | 2.1643.0 112 | 2.1644.0 113 | 2.1645.0 114 | 2.1646.0 115 | 2.1647.0 116 | 2.1648.0 117 | 2.1649.0 118 | 2.1650.0 119 | 2.1651.0 120 | 2.1652.0 121 | 2.1653.0 122 | 2.1654.0 123 | 2.1655.0 124 | 2.1656.0 125 | 2.1657.0 126 | 2.1658.0 127 | 2.1659.0 128 | 2.1660.0 129 | 2.1661.0 130 | 2.1662.0 131 | 2.1663.0 132 | 2.1664.0 133 | 2.1665.0 134 | 2.1666.0 135 | 2.1667.0 136 | 2.1668.0 137 | 2.1669.0 138 | 2.1670.0 139 | 2.1671.0 140 | 2.1672.0 141 | 2.1673.0 142 | 2.1674.0 143 | 2.1675.0 144 | 2.1676.0 145 | 2.1677.0 146 | 2.1678.0 147 | 2.1679.0 148 | 2.1680.0 149 | 2.1681.0 150 | 2.1682.0 151 | 2.1683.0 152 | 2.1684.0 153 | 2.1685.0 154 | 2.1686.0 155 | 2.1687.0 156 | 2.1688.0 157 | 2.1689.0 158 | 2.1690.0 159 | 2.1691.0 160 | -------------------------------------------------------------------------------- /src/instrumentations/bunyan/BunyanInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { BunyanInstrumentation } from '@opentelemetry/instrumentation-bunyan'; 2 | import { LoggingInstrumentor } from '../instrumentor'; 3 | 4 | export default class LumigoBunyanInstrumentation extends LoggingInstrumentor { 5 | getInstrumentedModule(): string { 6 | return 'bunyan'; 7 | } 8 | 9 | getInstrumentation(): BunyanInstrumentation { 10 | return new BunyanInstrumentation(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/instrumentations/bunyan/tested_versions/14/bunyan: -------------------------------------------------------------------------------- 1 | 1.8.15 2 | !2.0.0 3 | !2.0.1 4 | !2.0.2 5 | !2.0.3 6 | !2.0.4 7 | !2.0.5 8 | -------------------------------------------------------------------------------- /src/instrumentations/bunyan/tested_versions/16/bunyan: -------------------------------------------------------------------------------- 1 | 1.8.15 2 | !2.0.0 3 | !2.0.1 4 | !2.0.2 5 | !2.0.3 6 | !2.0.4 7 | !2.0.5 8 | -------------------------------------------------------------------------------- /src/instrumentations/bunyan/tested_versions/18/bunyan: -------------------------------------------------------------------------------- 1 | 1.8.15 2 | !2.0.0 3 | !2.0.1 4 | !2.0.2 5 | !2.0.3 6 | !2.0.4 7 | !2.0.5 8 | -------------------------------------------------------------------------------- /src/instrumentations/bunyan/tested_versions/20/bunyan: -------------------------------------------------------------------------------- 1 | 1.8.15 2 | !2.0.0 3 | !2.0.1 4 | !2.0.2 5 | !2.0.3 6 | !2.0.4 7 | !2.0.5 8 | -------------------------------------------------------------------------------- /src/instrumentations/express/ExpressInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { ExpressHooks } from './express'; 2 | import { ExpressInstrumentation } from 'opentelemetry-instrumentation-express'; 3 | import { TracingInstrumentor } from '../instrumentor'; 4 | 5 | export default class LumigoExpressInstrumentation extends TracingInstrumentor { 6 | getInstrumentedModule(): string { 7 | return 'express'; 8 | } 9 | 10 | getInstrumentation(): ExpressInstrumentation { 11 | return new ExpressInstrumentation({ 12 | requestHook: ExpressHooks.requestHook, 13 | includeHttpAttributes: true, 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/instrumentations/express/expressInstrumentation.test.ts: -------------------------------------------------------------------------------- 1 | import LumigoExpressInstrumentation from './ExpressInstrumentation'; 2 | 3 | describe('LumigoExpressInstrumentation', () => { 4 | let lumigoExpressInstrumentation = new LumigoExpressInstrumentation(); 5 | 6 | test('getInstrumentedModule should return "express"', () => { 7 | expect(lumigoExpressInstrumentation.getInstrumentedModule()).toEqual('express'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/instrumentations/express/tested_versions/14/express: -------------------------------------------------------------------------------- 1 | 4.9.0 2 | 4.9.1 3 | 4.9.2 4 | 4.9.3 5 | 4.9.4 6 | 4.9.5 7 | 4.9.6 8 | 4.9.7 9 | 4.9.8 10 | 4.10.0 11 | 4.10.1 12 | 4.10.2 13 | 4.10.3 14 | 4.10.4 15 | 4.10.5 16 | 4.10.6 17 | 4.10.7 18 | 4.10.8 19 | 4.11.0 20 | 4.11.1 21 | 4.11.2 22 | 4.12.0 23 | 4.12.1 24 | 4.12.2 25 | 4.12.3 26 | 4.12.4 27 | 4.13.0 28 | 4.13.1 29 | 4.13.2 30 | 4.13.3 31 | 4.13.4 32 | 4.14.0 33 | 4.14.1 34 | 4.15.0 35 | 4.15.1 36 | 4.15.2 37 | 4.15.3 38 | 4.15.4 39 | 4.15.5 40 | 4.16.0 41 | 4.16.1 42 | 4.16.2 43 | 4.16.3 44 | 4.16.4 45 | 4.17.0 46 | 4.17.1 47 | 4.17.2 48 | 4.17.3 49 | 4.18.0 50 | 4.18.1 51 | 4.18.2 52 | 4.18.3 53 | 4.19.0 54 | 4.19.1 55 | 4.19.2 56 | 4.20.0 57 | 4.21.0 58 | !5.0.0 59 | -------------------------------------------------------------------------------- /src/instrumentations/express/tested_versions/16/express: -------------------------------------------------------------------------------- 1 | 4.9.0 2 | 4.9.1 3 | 4.9.2 4 | 4.9.3 5 | 4.9.4 6 | 4.9.5 7 | 4.9.6 8 | 4.9.7 9 | 4.9.8 10 | 4.10.0 11 | 4.10.1 12 | 4.10.2 13 | 4.10.3 14 | 4.10.4 15 | 4.10.5 16 | 4.10.6 17 | 4.10.7 18 | 4.10.8 19 | 4.11.0 20 | 4.11.1 21 | 4.11.2 22 | 4.12.0 23 | 4.12.1 24 | 4.12.2 25 | 4.12.3 26 | 4.12.4 27 | 4.13.0 28 | 4.13.1 29 | 4.13.2 30 | 4.13.3 31 | 4.13.4 32 | 4.14.0 33 | 4.14.1 34 | 4.15.0 35 | 4.15.1 36 | 4.15.2 37 | 4.15.3 38 | 4.15.4 39 | 4.15.5 40 | 4.16.0 41 | 4.16.1 42 | 4.16.2 43 | 4.16.3 44 | 4.16.4 45 | 4.17.0 46 | 4.17.1 47 | 4.17.2 48 | 4.17.3 49 | 4.18.0 50 | 4.18.1 51 | 4.18.2 52 | 4.18.3 53 | 4.19.0 54 | 4.19.1 55 | 4.19.2 56 | 4.20.0 57 | 4.21.0 58 | !5.0.0 59 | -------------------------------------------------------------------------------- /src/instrumentations/express/tested_versions/18/express: -------------------------------------------------------------------------------- 1 | 4.9.0 2 | 4.9.1 3 | 4.9.2 4 | 4.9.3 5 | 4.9.4 6 | 4.9.5 7 | 4.9.6 8 | 4.9.7 9 | 4.9.8 10 | 4.10.0 11 | 4.10.1 12 | 4.10.2 13 | 4.10.3 14 | 4.10.4 15 | 4.10.5 16 | 4.10.6 17 | 4.10.7 18 | 4.10.8 19 | 4.11.0 20 | 4.11.1 21 | 4.11.2 22 | 4.12.0 23 | 4.12.1 24 | 4.12.2 25 | 4.12.3 26 | 4.12.4 27 | 4.13.0 28 | 4.13.1 29 | 4.13.2 30 | 4.13.3 31 | 4.13.4 32 | 4.14.0 33 | 4.14.1 34 | 4.15.0 35 | 4.15.1 36 | 4.15.2 37 | 4.15.3 38 | 4.15.4 39 | 4.15.5 40 | 4.16.0 41 | 4.16.1 42 | 4.16.2 43 | 4.16.3 44 | 4.16.4 45 | 4.17.0 46 | 4.17.1 47 | 4.17.2 48 | 4.17.3 49 | 4.18.0 50 | 4.18.1 51 | 4.18.2 52 | 4.18.3 53 | 4.19.0 54 | 4.19.1 55 | 4.19.2 56 | 4.20.0 57 | 4.21.0 58 | !5.0.0 59 | -------------------------------------------------------------------------------- /src/instrumentations/express/tested_versions/20/express: -------------------------------------------------------------------------------- 1 | 4.9.0 2 | 4.9.1 3 | 4.9.2 4 | 4.9.3 5 | 4.9.4 6 | 4.9.5 7 | 4.9.6 8 | 4.9.7 9 | 4.9.8 10 | 4.10.0 11 | 4.10.1 12 | 4.10.2 13 | 4.10.3 14 | 4.10.4 15 | 4.10.5 16 | 4.10.6 17 | 4.10.7 18 | 4.10.8 19 | 4.11.0 20 | 4.11.1 21 | 4.11.2 22 | 4.12.0 23 | 4.12.1 24 | 4.12.2 25 | 4.12.3 26 | 4.12.4 27 | 4.13.0 28 | 4.13.1 29 | 4.13.2 30 | 4.13.3 31 | 4.13.4 32 | 4.14.0 33 | 4.14.1 34 | 4.15.0 35 | 4.15.1 36 | 4.15.2 37 | 4.15.3 38 | 4.15.4 39 | 4.15.5 40 | 4.16.0 41 | 4.16.1 42 | 4.16.2 43 | 4.16.3 44 | 4.16.4 45 | 4.17.0 46 | 4.17.1 47 | 4.17.2 48 | 4.17.3 49 | 4.18.0 50 | 4.18.1 51 | 4.18.2 52 | 4.18.3 53 | 4.19.0 54 | 4.19.1 55 | 4.19.2 56 | 4.20.0 57 | 4.21.0 58 | !5.0.0 59 | -------------------------------------------------------------------------------- /src/instrumentations/fastify/FastifyInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { CommonUtils, ScrubContext } from '@lumigo/node-core'; 2 | import type { Span } from '@opentelemetry/api'; 3 | import { FastifyInstrumentation, FastifyRequestInfo } from '@opentelemetry/instrumentation-fastify'; 4 | import { contentType, scrubHttpPayload } from '../../tools/payloads'; 5 | import { getSpanAttributeMaxLength } from '../../utils'; 6 | import { TracingInstrumentor } from '../instrumentor'; 7 | 8 | export default class LumigoFastifyInstrumentation extends TracingInstrumentor { 9 | getInstrumentedModule(): string { 10 | return 'fastify'; 11 | } 12 | 13 | getInstrumentation(): FastifyInstrumentation { 14 | return new FastifyInstrumentation({ 15 | requestHook: function (span: Span, info: FastifyRequestInfo) { 16 | span.setAttribute( 17 | 'http.request.headers', 18 | CommonUtils.payloadStringify( 19 | info.request.headers, 20 | ScrubContext.HTTP_REQUEST_HEADERS, 21 | getSpanAttributeMaxLength() 22 | ) 23 | ); 24 | span.setAttribute( 25 | 'http.request.query', 26 | CommonUtils.payloadStringify( 27 | info.request.query, 28 | ScrubContext.HTTP_REQUEST_QUERY, 29 | getSpanAttributeMaxLength() 30 | ) 31 | ); 32 | span.setAttribute( 33 | 'http.request.body', 34 | scrubHttpPayload( 35 | info.request.body, 36 | contentType(info.request.headers), 37 | ScrubContext.HTTP_REQUEST_BODY 38 | ) 39 | ); 40 | }, 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/instrumentations/fastify/fastifyInstrumentation.test.ts: -------------------------------------------------------------------------------- 1 | import LumigoFastifyInstrumentation from './FastifyInstrumentation'; 2 | 3 | describe('LumigoFastifyInstrumentation', () => { 4 | let lumigoFastifyInstrumentation = new LumigoFastifyInstrumentation(); 5 | 6 | test('getInstrumentedModule should return "fastify"', () => { 7 | expect(lumigoFastifyInstrumentation.getInstrumentedModule()).toEqual('fastify'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/instrumentations/hooksIfc.ts: -------------------------------------------------------------------------------- 1 | import type { Span } from '@opentelemetry/api'; 2 | 3 | export interface InstrumentationIfc { 4 | requestHook: (span: Span, request: Rec) => void; 5 | responseHook: (span: Span, response: Res) => void; 6 | } 7 | -------------------------------------------------------------------------------- /src/instrumentations/https/HttpInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import type { RequestOptions } from 'https'; 2 | import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; 3 | 4 | import { HttpHooks } from './http'; 5 | import { TracingInstrumentor } from '../instrumentor'; 6 | 7 | export default class LumigoHttpInstrumentation extends TracingInstrumentor { 8 | private readonly ignoredHostnames: string[]; 9 | 10 | constructor(...ignoredHostnames: string[]) { 11 | super(); 12 | 13 | this.ignoredHostnames = (ignoredHostnames || []).concat( 14 | [process.env.ECS_CONTAINER_METADATA_URI, process.env.ECS_CONTAINER_METADATA_URI_V4] 15 | .filter(Boolean) 16 | .map((url) => { 17 | try { 18 | return new URL(url).hostname; 19 | } catch (err) { 20 | return; 21 | } 22 | }) 23 | ); 24 | } 25 | 26 | getInstrumentedModule = () => 'http'; 27 | 28 | getInstrumentation = () => 29 | new HttpInstrumentation({ 30 | ignoreOutgoingRequestHook: (request: RequestOptions) => { 31 | /* 32 | * Some requests, like towards the ECS Credentials endpoints, do not have the 33 | * hostname set, but they do have the host 34 | */ 35 | const requestHostname = request.hostname || request.host; 36 | const isRequestIgnored = 37 | this.ignoredHostnames.includes(requestHostname) || 38 | // Unroutable addresses, used by metadata and credential services on all clouds 39 | /169\.254\.\d+\.\d+.*/gm.test(requestHostname); 40 | 41 | return isRequestIgnored; 42 | }, 43 | requestHook: HttpHooks.requestHook, 44 | responseHook: HttpHooks.responseHook, 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /src/instrumentations/https/http.test.js: -------------------------------------------------------------------------------- 1 | import { Http, isValidHttpRequestBody } from './http'; 2 | 3 | describe('http hook', () => { 4 | process.env['AWS_REGION'] = 'us-east-x'; 5 | process.env['_X_AMZN_TRACE_ID'] = 6 | 'Root=1-5b1d2450-6ac46730d346cad0e53f89d0;Parent=59fa1aeb03c2ec1f;Sampled=1'; 7 | 8 | test('httpRequestEmitBeforeHookWrapper -> not crashed on bad data', () => { 9 | const requestData = { 10 | body: '', 11 | }; 12 | 13 | const emitEventName = 'emit'; 14 | const emitArg = { 15 | _httpMessage: { 16 | _hasBody: true, 17 | output: 1, 18 | }, 19 | }; 20 | 21 | const wrapper = Http.httpRequestEmitBeforeHookWrapper(requestData); 22 | wrapper(emitEventName, emitArg); 23 | 24 | expect(requestData).toEqual({ body: '' }); 25 | }); 26 | 27 | test('isValidHttpRequestBody - simple flow', () => { 28 | expect(isValidHttpRequestBody('BODY')).toEqual(true); 29 | expect(isValidHttpRequestBody(Buffer.from('BODY'))).toEqual(true); 30 | }); 31 | 32 | test('isValidHttpRequestBody -> empty flow', () => { 33 | expect(isValidHttpRequestBody()).toEqual(false); 34 | expect(isValidHttpRequestBody('')).toEqual(false); 35 | expect(isValidHttpRequestBody(0)).toEqual(false); 36 | expect(isValidHttpRequestBody([])).toEqual(false); 37 | expect(isValidHttpRequestBody({})).toEqual(false); 38 | expect(isValidHttpRequestBody(undefined)).toEqual(false); 39 | expect(isValidHttpRequestBody(null)).toEqual(false); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/instrumentations/https/httpInstrumentation.test.ts: -------------------------------------------------------------------------------- 1 | import LumigoHttpInstrumentation from './HttpInstrumentation'; 2 | 3 | describe('LumigoHttpInstrumentation', () => { 4 | let lumigoHttpInstrumentation = new LumigoHttpInstrumentation(); 5 | 6 | test('getInstrumentedModule should return "http"', () => { 7 | expect(lumigoHttpInstrumentation.getInstrumentedModule()).toEqual('http'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/instrumentations/instrumentor.ts: -------------------------------------------------------------------------------- 1 | import type { Instrumentation } from '@opentelemetry/instrumentation'; 2 | import { canRequireModule } from '../requireUtils'; 3 | import { LOGGING_ENABLED, TRACING_ENABLED } from '../constants'; 4 | 5 | abstract class Instrumentor { 6 | abstract getInstrumentedModule(): string; 7 | 8 | abstract getInstrumentation(options?): T; 9 | 10 | isApplicable() { 11 | return canRequireModule(this.getInstrumentedModule()); 12 | } 13 | } 14 | 15 | export abstract class LoggingInstrumentor extends Instrumentor { 16 | override isApplicable() { 17 | return LOGGING_ENABLED && super.isApplicable(); 18 | } 19 | } 20 | 21 | export abstract class TracingInstrumentor extends Instrumentor { 22 | override isApplicable() { 23 | return TRACING_ENABLED && super.isApplicable(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/instrumentations/ioredis/IORedisInstrumentation.test.js: -------------------------------------------------------------------------------- 1 | import LumigoIORedisInstrumentation from './IORedisInstrumentation'; 2 | import child_process from 'child_process'; 3 | 4 | describe('LumigoIORedisInstrumentation', () => { 5 | const oldEnv = Object.assign({}, process.env); 6 | 7 | beforeEach(() => { 8 | process.env = { ...oldEnv }; 9 | }); 10 | 11 | afterEach(() => { 12 | jest.clearAllMocks(); 13 | process.env = { ...oldEnv }; 14 | }); 15 | 16 | let lumigoIORedisInstrumentation = new LumigoIORedisInstrumentation(); 17 | 18 | test('getInstrumentedModule should return "ioredis"', () => { 19 | expect(lumigoIORedisInstrumentation.getInstrumentedModule()).toEqual('ioredis'); 20 | }); 21 | 22 | test('disable ioredis instrumentation', () => { 23 | const child_process = require('child_process'); 24 | child_process.execSync('npm install ioredis', { stdio: 'inherit' }); 25 | 26 | process.env.LUMIGO_DISABLE_IOREDIS_INSTRUMENTATION = 'true'; 27 | expect(lumigoIORedisInstrumentation.isApplicable()).toEqual(false); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/instrumentations/ioredis/IORedisInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { CommonUtils, ScrubContext } from '@lumigo/node-core'; 2 | import type { Span } from '@opentelemetry/api'; 3 | import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis'; 4 | import { getSpanAttributeMaxLength } from '../../utils'; 5 | import { TracingInstrumentor } from '../instrumentor'; 6 | 7 | export default class LumigoIORedisInstrumentation extends TracingInstrumentor { 8 | override isApplicable(): boolean { 9 | return ( 10 | super.isApplicable() && 11 | process.env.LUMIGO_DISABLE_IOREDIS_INSTRUMENTATION?.toLocaleLowerCase() !== 'true' 12 | ); 13 | } 14 | 15 | getInstrumentedModule(): string { 16 | return 'ioredis'; 17 | } 18 | 19 | getInstrumentation(): IORedisInstrumentation { 20 | return new IORedisInstrumentation({ 21 | dbStatementSerializer: function (cmdName, cmdArgs) { 22 | const statement = [cmdName, ...cmdArgs].join(' '); 23 | return CommonUtils.payloadStringify( 24 | statement, 25 | ScrubContext.HTTP_REQUEST_BODY, 26 | getSpanAttributeMaxLength() 27 | ); 28 | }, 29 | responseHook: ( 30 | span: Span, 31 | cmdName: string, 32 | cmdArgs: (string | Buffer)[], 33 | response: unknown 34 | ) => { 35 | span.setAttribute( 36 | `db.response.body`, 37 | CommonUtils.payloadStringify( 38 | response?.toString(), 39 | ScrubContext.HTTP_RESPONSE_BODY, 40 | getSpanAttributeMaxLength() 41 | ) 42 | ); 43 | }, 44 | requireParentSpan: false, 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/instrumentations/ioredis/tested_versions/14/ioredis: -------------------------------------------------------------------------------- 1 | 4.0.0 2 | 4.0.1 3 | 4.0.2 4 | 4.1.0 5 | 4.2.0 6 | 4.2.1 7 | 4.2.2 8 | 4.2.3 9 | 4.3.0 10 | 4.3.1 11 | 4.4.0 12 | 4.5.0 13 | 4.5.1 14 | 4.6.0 15 | 4.6.1 16 | 4.6.2 17 | 4.6.3 18 | 4.7.0 19 | 4.8.0 20 | 4.9.0 21 | 4.9.1 22 | 4.9.2 23 | 4.9.3 24 | 4.9.4 25 | 4.9.5 26 | 4.10.0 27 | 4.10.1 28 | 4.10.2 29 | 4.10.3 30 | 4.10.4 31 | 4.11.0 32 | 4.11.1 33 | 4.11.2 34 | 4.12.0 35 | 4.12.1 36 | 4.12.2 37 | 4.13.0 38 | 4.13.1 39 | 4.14.0 40 | 4.14.1 41 | 4.14.2 42 | 4.14.3 43 | 4.14.4 44 | 4.15.0 45 | 4.15.1 46 | 4.16.0 47 | 4.16.1 48 | 4.16.2 49 | 4.16.3 50 | 4.17.0 51 | 4.17.1 52 | 4.17.2 53 | 4.17.3 54 | 4.18.0 55 | 4.19.0 56 | 4.19.1 57 | 4.19.2 58 | 4.19.3 59 | 4.19.4 60 | 4.20.0 61 | 4.21.0 62 | 4.22.0 63 | 4.23.0 64 | 4.23.1 65 | 4.24.0 66 | 4.24.1 67 | 4.24.2 68 | 4.24.3 69 | 4.24.4 70 | 4.24.5 71 | 4.24.6 72 | 4.25.0 73 | 4.26.0 74 | 4.27.0 75 | 4.27.1 76 | 4.27.2 77 | 4.27.3 78 | 4.27.4 79 | 4.27.5 80 | 4.27.6 81 | 4.27.7 82 | 4.27.8 83 | 4.27.9 84 | 4.27.10 85 | 4.27.11 86 | 4.28.0 87 | 4.28.1 88 | 4.28.2 89 | 4.28.3 90 | 4.28.4 91 | 4.28.5 92 | 5.0.0 93 | 5.0.1 94 | 5.0.2 95 | 5.0.3 96 | 5.0.4 97 | 5.0.5 98 | 5.0.6 99 | 5.1.0 100 | 5.2.0 101 | 5.2.1 102 | 5.2.2 103 | 5.2.3 104 | 5.2.4 105 | 5.2.5 106 | 5.2.6 107 | 5.3.0 108 | 5.3.1 109 | 5.3.2 110 | 5.4.0 111 | 5.4.1 112 | -------------------------------------------------------------------------------- /src/instrumentations/ioredis/tested_versions/16/ioredis: -------------------------------------------------------------------------------- 1 | 4.0.0 2 | 4.0.1 3 | 4.0.2 4 | 4.1.0 5 | 4.2.0 6 | 4.2.1 7 | 4.2.2 8 | 4.2.3 9 | 4.3.0 10 | 4.3.1 11 | 4.4.0 12 | 4.5.0 13 | 4.5.1 14 | 4.6.0 15 | 4.6.1 16 | 4.6.2 17 | 4.6.3 18 | 4.7.0 19 | 4.8.0 20 | 4.9.0 21 | 4.9.1 22 | 4.9.2 23 | 4.9.3 24 | 4.9.4 25 | 4.9.5 26 | 4.10.0 27 | 4.10.1 28 | 4.10.2 29 | 4.10.3 30 | 4.10.4 31 | 4.11.0 32 | 4.11.1 33 | 4.11.2 34 | 4.12.0 35 | 4.12.1 36 | 4.12.2 37 | 4.13.0 38 | 4.13.1 39 | 4.14.0 40 | 4.14.1 41 | 4.14.2 42 | 4.14.3 43 | 4.14.4 44 | 4.15.0 45 | 4.15.1 46 | 4.16.0 47 | 4.16.1 48 | 4.16.2 49 | 4.16.3 50 | 4.17.0 51 | 4.17.1 52 | 4.17.2 53 | 4.17.3 54 | 4.18.0 55 | 4.19.0 56 | 4.19.1 57 | 4.19.2 58 | 4.19.3 59 | 4.19.4 60 | 4.20.0 61 | 4.21.0 62 | 4.22.0 63 | 4.23.0 64 | 4.23.1 65 | 4.24.0 66 | 4.24.1 67 | 4.24.2 68 | 4.24.3 69 | 4.24.4 70 | 4.24.5 71 | 4.24.6 72 | 4.25.0 73 | 4.26.0 74 | 4.27.0 75 | 4.27.1 76 | 4.27.2 77 | 4.27.3 78 | 4.27.4 79 | 4.27.5 80 | 4.27.6 81 | 4.27.7 82 | 4.27.8 83 | 4.27.9 84 | 4.27.10 85 | 4.27.11 86 | 4.28.0 87 | 4.28.1 88 | 4.28.2 89 | 4.28.3 90 | 4.28.4 91 | 4.28.5 92 | 5.0.0 93 | 5.0.1 94 | 5.0.2 95 | 5.0.3 96 | 5.0.4 97 | 5.0.5 98 | 5.0.6 99 | 5.1.0 100 | 5.2.0 101 | 5.2.1 102 | 5.2.2 103 | 5.2.3 104 | 5.2.4 105 | 5.2.5 106 | 5.2.6 107 | 5.3.0 108 | 5.3.1 109 | 5.3.2 110 | 5.4.0 111 | 5.4.1 112 | -------------------------------------------------------------------------------- /src/instrumentations/ioredis/tested_versions/18/ioredis: -------------------------------------------------------------------------------- 1 | 4.0.0 2 | 4.0.1 3 | 4.0.2 4 | 4.1.0 5 | 4.2.0 6 | 4.2.1 7 | 4.2.2 8 | 4.2.3 9 | 4.3.0 10 | 4.3.1 11 | 4.4.0 12 | 4.5.0 13 | 4.5.1 14 | 4.6.0 15 | 4.6.1 16 | 4.6.2 17 | 4.6.3 18 | 4.7.0 19 | 4.8.0 20 | 4.9.0 21 | 4.9.1 22 | 4.9.2 23 | 4.9.3 24 | 4.9.4 25 | 4.9.5 26 | 4.10.0 27 | 4.10.1 28 | 4.10.2 29 | 4.10.3 30 | 4.10.4 31 | 4.11.0 32 | 4.11.1 33 | 4.11.2 34 | 4.12.0 35 | 4.12.1 36 | 4.12.2 37 | 4.13.0 38 | 4.13.1 39 | 4.14.0 40 | 4.14.1 41 | 4.14.2 42 | 4.14.3 43 | 4.14.4 44 | 4.15.0 45 | 4.15.1 46 | 4.16.0 47 | 4.16.1 48 | 4.16.2 49 | 4.16.3 50 | 4.17.0 51 | 4.17.1 52 | 4.17.2 53 | 4.17.3 54 | 4.18.0 55 | 4.19.0 56 | 4.19.1 57 | 4.19.2 58 | 4.19.3 59 | 4.19.4 60 | 4.20.0 61 | 4.21.0 62 | 4.22.0 63 | 4.23.0 64 | 4.23.1 65 | 4.24.0 66 | 4.24.1 67 | 4.24.2 68 | 4.24.3 69 | 4.24.4 70 | 4.24.5 71 | 4.24.6 72 | 4.25.0 73 | 4.26.0 74 | 4.27.0 75 | 4.27.1 76 | 4.27.2 77 | 4.27.3 78 | 4.27.4 79 | 4.27.5 80 | 4.27.6 81 | 4.27.7 82 | 4.27.8 83 | 4.27.9 84 | 4.27.10 85 | 4.27.11 86 | 4.28.0 87 | 4.28.1 88 | 4.28.2 89 | 4.28.3 90 | 4.28.4 91 | 4.28.5 92 | 5.0.0 93 | 5.0.1 94 | 5.0.2 95 | 5.0.3 96 | 5.0.4 97 | 5.0.5 98 | 5.0.6 99 | 5.1.0 100 | 5.2.0 101 | 5.2.1 102 | 5.2.2 103 | 5.2.3 104 | 5.2.4 105 | 5.2.5 106 | 5.2.6 107 | 5.3.0 108 | 5.3.1 109 | 5.3.2 110 | 5.4.0 111 | 5.4.1 112 | -------------------------------------------------------------------------------- /src/instrumentations/ioredis/tested_versions/20/ioredis: -------------------------------------------------------------------------------- 1 | 4.0.0 2 | 4.0.1 3 | 4.0.2 4 | 4.1.0 5 | 4.2.0 6 | 4.2.1 7 | 4.2.2 8 | 4.2.3 9 | 4.3.0 10 | 4.3.1 11 | 4.4.0 12 | 4.5.0 13 | 4.5.1 14 | 4.6.0 15 | 4.6.1 16 | 4.6.2 17 | 4.6.3 18 | 4.7.0 19 | 4.8.0 20 | 4.9.0 21 | 4.9.1 22 | 4.9.2 23 | 4.9.3 24 | 4.9.4 25 | 4.9.5 26 | 4.10.0 27 | 4.10.1 28 | 4.10.2 29 | 4.10.3 30 | 4.10.4 31 | 4.11.0 32 | 4.11.1 33 | 4.11.2 34 | 4.12.0 35 | 4.12.1 36 | 4.12.2 37 | 4.13.0 38 | 4.13.1 39 | 4.14.0 40 | 4.14.1 41 | 4.14.2 42 | 4.14.3 43 | 4.14.4 44 | 4.15.0 45 | 4.15.1 46 | 4.16.0 47 | 4.16.1 48 | 4.16.2 49 | 4.16.3 50 | 4.17.0 51 | 4.17.1 52 | 4.17.2 53 | 4.17.3 54 | 4.18.0 55 | 4.19.0 56 | 4.19.1 57 | 4.19.2 58 | 4.19.3 59 | 4.19.4 60 | 4.20.0 61 | 4.21.0 62 | 4.22.0 63 | 4.23.0 64 | 4.23.1 65 | 4.24.0 66 | 4.24.1 67 | 4.24.2 68 | 4.24.3 69 | 4.24.4 70 | 4.24.5 71 | 4.24.6 72 | 4.25.0 73 | 4.26.0 74 | 4.27.0 75 | 4.27.1 76 | 4.27.2 77 | 4.27.3 78 | 4.27.4 79 | 4.27.5 80 | 4.27.6 81 | 4.27.7 82 | 4.27.8 83 | 4.27.9 84 | 4.27.10 85 | 4.27.11 86 | 4.28.0 87 | 4.28.1 88 | 4.28.2 89 | 4.28.3 90 | 4.28.4 91 | 4.28.5 92 | 5.0.0 93 | 5.0.1 94 | 5.0.2 95 | 5.0.3 96 | 5.0.4 97 | 5.0.5 98 | 5.0.6 99 | 5.1.0 100 | 5.2.0 101 | 5.2.1 102 | 5.2.2 103 | 5.2.3 104 | 5.2.4 105 | 5.2.5 106 | 5.2.6 107 | 5.3.0 108 | 5.3.1 109 | 5.3.2 110 | 5.4.0 111 | 5.4.1 112 | -------------------------------------------------------------------------------- /src/instrumentations/kafkajs/KafkaJsInstrumentation.test.js: -------------------------------------------------------------------------------- 1 | import LumigoKafkaJsInstrumentation from './KafkaJsInstrumentation'; 2 | 3 | describe('LumigoKafkaJsInstrumentation', () => { 4 | afterEach(() => { 5 | jest.clearAllMocks(); 6 | }); 7 | 8 | let lumigoKafkaJsInstrumentation = new LumigoKafkaJsInstrumentation(); 9 | 10 | test('getInstrumentedModule should return "kafkajs"', () => { 11 | expect(lumigoKafkaJsInstrumentation.getInstrumentedModule()).toEqual('kafkajs'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/instrumentations/kafkajs/KafkaJsInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { CommonUtils, ScrubContext } from '@lumigo/node-core'; 2 | import type { Span } from '@opentelemetry/api'; 3 | import type { Message } from 'kafkajs'; 4 | import { KafkaJsInstrumentation } from 'opentelemetry-instrumentation-kafkajs'; 5 | import { getSpanAttributeMaxLength } from '../../utils'; 6 | import { TracingInstrumentor } from '../instrumentor'; 7 | 8 | export default class LumigoKafkaJsInstrumentation extends TracingInstrumentor { 9 | getInstrumentedModule(): string { 10 | return 'kafkajs'; 11 | } 12 | 13 | getInstrumentation(): KafkaJsInstrumentation { 14 | return new KafkaJsInstrumentation({ 15 | producerHook: (span: Span, topic: string, message: Message) => { 16 | span.setAttribute( 17 | 'messaging.produce.body', 18 | CommonUtils.payloadStringify( 19 | message.value.toString(), 20 | ScrubContext.HTTP_REQUEST_QUERY, 21 | getSpanAttributeMaxLength() 22 | ) 23 | ); 24 | }, 25 | consumerHook: (span: Span, topic: string, message: Message) => { 26 | span.setAttribute( 27 | 'messaging.consume.body', 28 | CommonUtils.payloadStringify( 29 | message.value.toString(), 30 | ScrubContext.HTTP_RESPONSE_BODY, 31 | getSpanAttributeMaxLength() 32 | ) 33 | ); 34 | }, 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/instrumentations/kafkajs/tested_versions/14/kafkajs: -------------------------------------------------------------------------------- 1 | !1.14.0 2 | !1.15.0 3 | !1.16.0 4 | 2.0.0 5 | 2.0.1 6 | 2.0.2 7 | 2.1.0 8 | 2.2.0 9 | 2.2.1 10 | 2.2.2 11 | 2.2.3 12 | 2.2.4 13 | -------------------------------------------------------------------------------- /src/instrumentations/kafkajs/tested_versions/16/kafkajs: -------------------------------------------------------------------------------- 1 | !1.14.0 2 | !1.15.0 3 | !1.16.0 4 | 2.0.0 5 | 2.0.1 6 | 2.0.2 7 | 2.1.0 8 | 2.2.0 9 | 2.2.1 10 | 2.2.2 11 | 2.2.3 12 | 2.2.4 13 | -------------------------------------------------------------------------------- /src/instrumentations/kafkajs/tested_versions/18/kafkajs: -------------------------------------------------------------------------------- 1 | !1.14.0 2 | !1.15.0 3 | !1.16.0 4 | 2.0.0 5 | 2.0.1 6 | 2.0.2 7 | 2.1.0 8 | 2.2.0 9 | 2.2.1 10 | 2.2.2 11 | 2.2.3 12 | 2.2.4 13 | -------------------------------------------------------------------------------- /src/instrumentations/kafkajs/tested_versions/20/kafkajs: -------------------------------------------------------------------------------- 1 | !1.14.0 2 | !1.15.0 3 | !1.16.0 4 | 2.0.0 5 | 2.0.1 6 | 2.0.2 7 | 2.1.0 8 | 2.2.0 9 | 2.2.1 10 | 2.2.2 11 | 2.2.3 12 | 2.2.4 13 | -------------------------------------------------------------------------------- /src/instrumentations/logsInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { 2 | InstrumentationBase, 3 | InstrumentationModuleDefinition, 4 | InstrumentationNodeModuleDefinition, 5 | } from '@opentelemetry/instrumentation'; 6 | import { SpanKind } from '@opentelemetry/api'; 7 | 8 | import { logger } from '../logging'; 9 | 10 | export default class LogsInstrumentation extends InstrumentationBase { 11 | instrumentationDescription: string; 12 | supportedVersions: string[]; 13 | 14 | constructor() { 15 | super('logs-instrumentation', '0.0.1'); 16 | } 17 | 18 | protected init(): InstrumentationModuleDefinition | InstrumentationModuleDefinition[] | void { 19 | logger.debug('in console instrumentation'); 20 | 21 | return [ 22 | new InstrumentationNodeModuleDefinition( 23 | 'console', 24 | ['*'], 25 | (moduleExports, moduleVersion) => { 26 | const instrumentation = this; 27 | this._wrap(moduleExports, 'warn', this.logsWrapper(instrumentation, 'warn')); 28 | this._wrap(moduleExports, 'error', this.logsWrapper(instrumentation, 'error')); 29 | return moduleExports; 30 | }, 31 | (exports) => {}, 32 | [] 33 | ), 34 | ]; 35 | } 36 | 37 | private logsWrapper = (instrumentation, level) => { 38 | return (original) => { 39 | return ( 40 | // eslint-disable-next-line node/no-unsupported-features/node-builtins 41 | message, 42 | options 43 | ) => { 44 | let result; 45 | let stringifyOptions; 46 | try { 47 | stringifyOptions = JSON.stringify(options); 48 | } catch (e) {} 49 | instrumentation.tracer.startActiveSpan( 50 | 'logs-span', 51 | { 52 | kind: SpanKind.INTERNAL, 53 | attributes: { log: message, level, options: stringifyOptions }, 54 | }, 55 | (span) => { 56 | span.end(); 57 | return span; 58 | } 59 | ); 60 | result = options 61 | ? original.apply(this, [message, options]) 62 | : original.apply(this, [message]); 63 | return result; 64 | }; 65 | }; 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /src/instrumentations/mongodb/MongoDBInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb'; 2 | import { TracingInstrumentor } from '../instrumentor'; 3 | 4 | export default class LumigoMongoDBInstrumentation extends TracingInstrumentor { 5 | override isApplicable(): boolean { 6 | return ( 7 | super.isApplicable() && 8 | process.env.LUMIGO_DISABLE_MONGODB_INSTRUMENTATION?.toLocaleLowerCase() !== 'true' 9 | ); 10 | } 11 | getInstrumentedModule(): string { 12 | return 'mongodb'; 13 | } 14 | 15 | getInstrumentation(): MongoDBInstrumentation { 16 | return new MongoDBInstrumentation({ 17 | enhancedDatabaseReporting: true, 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/instrumentations/mongodb/mongoDBInstrumentation.test.js: -------------------------------------------------------------------------------- 1 | import LumigoMongoDBInstrumentation from './MongoDBInstrumentation'; 2 | import child_process from 'child_process'; 3 | 4 | describe('LumigoMongoDBInstrumentation', () => { 5 | const oldEnv = Object.assign({}, process.env); 6 | beforeEach(() => { 7 | process.env = { ...oldEnv }; 8 | }); 9 | 10 | afterEach(() => { 11 | jest.clearAllMocks(); 12 | process.env = { ...oldEnv }; 13 | }); 14 | 15 | let lumigoMongoDBInstrumentation = new LumigoMongoDBInstrumentation(); 16 | 17 | test('disable mongodb instrumentation', () => { 18 | const child_process = require('child_process'); 19 | child_process.execSync('npm install mongodb', { stdio: 'inherit' }); 20 | 21 | process.env.LUMIGO_DISABLE_MONGODB_INSTRUMENTATION = 'true'; 22 | expect(lumigoMongoDBInstrumentation.isApplicable()).toEqual(false); 23 | }); 24 | 25 | test('getInstrumentedModule should return "mongodb"', () => { 26 | expect(lumigoMongoDBInstrumentation.getInstrumentedModule()).toEqual('mongodb'); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/instrumentations/mongodb/tested_versions/14/mongodb: -------------------------------------------------------------------------------- 1 | 4.17.0 2 | 4.17.1 3 | 4.17.2 4 | 5.0.0 5 | 5.0.1 6 | 5.1.0 7 | 5.2.0 8 | 5.3.0 9 | 5.4.0 10 | 5.5.0 11 | 5.6.0 12 | 5.7.0 13 | 5.8.0 14 | 5.8.1 15 | 5.9.0 16 | 5.9.1 17 | 5.9.2 18 | !6.0.0 19 | !6.1.0 20 | !6.2.0 21 | !6.3.0 22 | !6.4.0 23 | !6.5.0 24 | !6.6.0 25 | !6.6.1 26 | !6.6.2 27 | !6.7.0 28 | !6.8.0 29 | !6.8.1 30 | !6.8.2 31 | !6.9.0 32 | -------------------------------------------------------------------------------- /src/instrumentations/mongodb/tested_versions/16/mongodb: -------------------------------------------------------------------------------- 1 | 3.6.6 2 | 3.6.7 3 | 3.6.8 4 | 3.6.9 5 | 3.6.10 6 | 3.6.11 7 | 3.6.12 8 | 3.7.0 9 | 3.7.1 10 | 3.7.2 11 | 3.7.3 12 | 4.0.0 13 | 4.0.1 14 | 4.1.0 15 | 4.1.1 16 | 4.1.2 17 | 4.1.3 18 | 4.1.4 19 | 4.2.0 20 | 4.2.1 21 | 4.2.2 22 | 4.3.0 23 | 4.3.1 24 | 4.4.0 25 | 4.4.1 26 | 4.5.0 27 | 4.6.0 28 | 4.7.0 29 | 4.8.0 30 | 4.8.1 31 | 4.9.0 32 | 4.9.1 33 | 4.10.0 34 | 4.11.0 35 | 4.12.0 36 | 4.12.1 37 | 4.13.0 38 | 4.14.0 39 | 4.15.0 40 | 4.16.0 41 | 4.17.0 42 | 4.17.1 43 | 4.17.2 44 | 5.0.0 45 | 5.0.1 46 | 5.1.0 47 | 5.2.0 48 | 5.3.0 49 | 5.4.0 50 | 5.5.0 51 | 5.6.0 52 | 5.7.0 53 | 5.8.0 54 | 5.8.1 55 | 5.9.0 56 | 5.9.1 57 | 5.9.2 58 | 6.0.0 59 | 6.1.0 60 | 6.2.0 61 | 6.3.0 62 | !6.4.0 63 | !6.5.0 64 | !6.6.0 65 | !6.6.1 66 | !6.6.2 67 | !6.7.0 68 | !6.8.0 69 | !6.8.1 70 | !6.8.2 71 | !6.9.0 72 | -------------------------------------------------------------------------------- /src/instrumentations/mongodb/tested_versions/18/mongodb: -------------------------------------------------------------------------------- 1 | 3.6.6 2 | 3.6.7 3 | 3.6.8 4 | 3.6.9 5 | 3.6.10 6 | 3.6.11 7 | 3.6.12 8 | 3.7.0 9 | 3.7.1 10 | 3.7.2 11 | 3.7.3 12 | 4.0.0 13 | 4.0.1 14 | 4.1.0 15 | 4.1.1 16 | 4.1.2 17 | 4.1.3 18 | 4.1.4 19 | 4.2.0 20 | 4.2.1 21 | 4.2.2 22 | 4.3.0 23 | 4.3.1 24 | 4.4.0 25 | 4.4.1 26 | 4.5.0 27 | 4.6.0 28 | 4.7.0 29 | 4.8.0 30 | 4.8.1 31 | 4.9.0 32 | 4.9.1 33 | 4.10.0 34 | 4.11.0 35 | 4.12.0 36 | 4.12.1 37 | 4.13.0 38 | 4.14.0 39 | 4.15.0 40 | 4.16.0 41 | 4.17.0 42 | 4.17.1 43 | 4.17.2 44 | 5.0.0 45 | 5.0.1 46 | 5.1.0 47 | 5.2.0 48 | 5.3.0 49 | 5.4.0 50 | 5.5.0 51 | 5.6.0 52 | 5.7.0 53 | 5.8.0 54 | 5.8.1 55 | 5.9.0 56 | 5.9.1 57 | 5.9.2 58 | 6.0.0 59 | 6.1.0 60 | 6.2.0 61 | 6.3.0 62 | !6.4.0 63 | !6.5.0 64 | !6.6.0 65 | !6.6.1 66 | !6.6.2 67 | !6.7.0 68 | !6.8.0 69 | !6.8.1 70 | !6.8.2 71 | !6.9.0 72 | -------------------------------------------------------------------------------- /src/instrumentations/mongodb/tested_versions/20/mongodb: -------------------------------------------------------------------------------- 1 | 3.6.6 2 | 3.6.7 3 | 3.6.8 4 | 3.6.9 5 | 3.6.10 6 | 3.6.11 7 | 3.6.12 8 | 3.7.0 9 | 3.7.1 10 | 3.7.2 11 | 3.7.3 12 | 4.0.0 13 | 4.0.1 14 | 4.1.0 15 | 4.1.1 16 | 4.1.2 17 | 4.1.3 18 | 4.1.4 19 | 4.2.0 20 | 4.2.1 21 | 4.2.2 22 | 4.3.0 23 | 4.3.1 24 | 4.4.0 25 | 4.4.1 26 | 4.5.0 27 | 4.6.0 28 | 4.7.0 29 | 4.8.0 30 | 4.8.1 31 | 4.9.0 32 | 4.9.1 33 | 4.10.0 34 | 4.11.0 35 | 4.12.0 36 | 4.12.1 37 | 4.13.0 38 | 4.14.0 39 | 4.15.0 40 | 4.16.0 41 | 4.17.0 42 | 4.17.1 43 | 4.17.2 44 | 5.0.0 45 | 5.0.1 46 | 5.1.0 47 | 5.2.0 48 | 5.3.0 49 | 5.4.0 50 | 5.5.0 51 | 5.6.0 52 | 5.7.0 53 | 5.8.0 54 | 5.8.1 55 | 5.9.0 56 | 5.9.1 57 | 5.9.2 58 | 6.0.0 59 | 6.1.0 60 | 6.2.0 61 | 6.3.0 62 | !6.4.0 63 | !6.5.0 64 | !6.6.0 65 | !6.6.1 66 | !6.6.2 67 | !6.7.0 68 | !6.8.0 69 | !6.8.1 70 | !6.8.2 71 | !6.9.0 72 | -------------------------------------------------------------------------------- /src/instrumentations/next/tested_versions/14/next: -------------------------------------------------------------------------------- 1 | 11.1.2 2 | !11.1.3 3 | !11.1.4 4 | !12.0.0 5 | !12.0.1 6 | !12.0.2 7 | !12.0.3 8 | !12.0.4 9 | !12.0.5 10 | !12.0.6 11 | !12.0.7 12 | !12.0.8 13 | !12.0.9 14 | !12.0.10 15 | !12.1.0 16 | !12.1.1 17 | !12.1.2 18 | !12.1.3 19 | !12.1.4 20 | !12.1.5 21 | !12.1.6 22 | !12.2.0 23 | !12.2.1 24 | !12.2.2 25 | !12.2.3 26 | !12.2.4 27 | !12.2.5 28 | !12.2.6 29 | !12.3.0 30 | !12.3.1 31 | !12.3.2 32 | !12.3.3 33 | !12.3.4 34 | !13.0.0 35 | !13.0.1 36 | !13.0.2 37 | !13.0.3 38 | !13.0.4 39 | !13.0.5 40 | !13.0.6 41 | !13.0.7 42 | !13.1.0 43 | !13.1.1 44 | !13.1.2 45 | !13.1.3 46 | !13.1.4 47 | !13.1.5 48 | !13.1.6 49 | !13.2.0 50 | !13.2.1 51 | !13.2.2 52 | !13.2.3 53 | !13.2.4 54 | !13.3.0 55 | !13.3.1 56 | !13.3.2 57 | !13.3.3 58 | !13.3.4 59 | !13.4.0 60 | !13.4.1 61 | !13.4.2 62 | !13.4.3 63 | !13.4.4 64 | !14.2.13 65 | -------------------------------------------------------------------------------- /src/instrumentations/next/tested_versions/16/next: -------------------------------------------------------------------------------- 1 | 13.5.6 2 | !13.5.7 3 | !14.0.0 4 | !14.0.1 5 | !14.0.2 6 | !14.0.3 7 | !14.0.4 8 | !14.1.0 9 | !14.1.1 10 | !14.1.2 11 | !14.1.3 12 | !14.1.4 13 | !14.2.0 14 | !14.2.1 15 | !14.2.2 16 | !14.2.3 17 | !14.2.4 18 | !14.2.5 19 | !14.2.6 20 | !14.2.7 21 | !14.2.8 22 | !14.2.9 23 | !14.2.10 24 | !14.2.11 25 | !14.2.12 26 | !14.2.13 27 | !14.2.14 28 | -------------------------------------------------------------------------------- /src/instrumentations/next/tested_versions/18/next: -------------------------------------------------------------------------------- 1 | 14.2.13 2 | 14.2.14 3 | -------------------------------------------------------------------------------- /src/instrumentations/next/tested_versions/20/next: -------------------------------------------------------------------------------- 1 | 14.2.13 2 | 14.2.14 3 | -------------------------------------------------------------------------------- /src/instrumentations/pg/PgInstrumentation.test.js: -------------------------------------------------------------------------------- 1 | import LumigoPgInstrumentation from './PgInstrumentation'; 2 | import child_process from 'child_process'; 3 | 4 | describe('LumigoPgInstrumentation', () => { 5 | const oldEnv = Object.assign({}, process.env); 6 | beforeEach(() => { 7 | process.env = { ...oldEnv }; 8 | }); 9 | 10 | afterEach(() => { 11 | jest.clearAllMocks(); 12 | process.env = { ...oldEnv }; 13 | }); 14 | 15 | let lumigoPgInstrumentation = new LumigoPgInstrumentation(); 16 | 17 | test('disable pg instrumentation', () => { 18 | const child_process = require('child_process'); 19 | child_process.execSync('npm install pg', { stdio: 'inherit' }); 20 | 21 | process.env.LUMIGO_DISABLE_PG_INSTRUMENTATION = 'true'; 22 | expect(lumigoPgInstrumentation.isApplicable()).toEqual(false); 23 | }); 24 | 25 | test('getInstrumentedModule should return "pg"', () => { 26 | expect(lumigoPgInstrumentation.getInstrumentedModule()).toEqual('pg'); 27 | }); 28 | 29 | // should not be skipped, see https://lumigo.atlassian.net/browse/RD-11195 30 | test.skip('requireIfAvailable should return required name', () => { 31 | const child_process = require('child_process'); 32 | child_process.execSync('npm install pg', { stdio: 'inherit' }); 33 | const pg = require('pg'); 34 | 35 | expect(lumigoPgInstrumentation.requireIfAvailable()).toEqual(pg); 36 | child_process.execSync('npm uninstall pg', { stdio: 'inherit' }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/instrumentations/pg/PgInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { PgInstrumentation } from '@opentelemetry/instrumentation-pg'; 2 | import { TracingInstrumentor } from '../instrumentor'; 3 | 4 | export default class LumigoPgInstrumentation extends TracingInstrumentor { 5 | override isApplicable(): boolean { 6 | return ( 7 | super.isApplicable() && 8 | process.env.LUMIGO_DISABLE_PG_INSTRUMENTATION?.toLocaleLowerCase() !== 'true' 9 | ); 10 | } 11 | 12 | getInstrumentedModule(): string { 13 | return 'pg'; 14 | } 15 | 16 | getInstrumentation(): PgInstrumentation { 17 | return new PgInstrumentation({ 18 | enhancedDatabaseReporting: true, 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/instrumentations/pg/tested_versions/14/pg: -------------------------------------------------------------------------------- 1 | 8.11.3 2 | 8.11.4 3 | 8.11.5 4 | 8.11.6 5 | 8.12.0 6 | 8.13.0 7 | -------------------------------------------------------------------------------- /src/instrumentations/pg/tested_versions/16/pg: -------------------------------------------------------------------------------- 1 | 8.11.3 2 | 8.11.4 3 | 8.11.5 4 | 8.11.6 5 | 8.12.0 6 | 8.13.0 7 | -------------------------------------------------------------------------------- /src/instrumentations/pg/tested_versions/18/pg: -------------------------------------------------------------------------------- 1 | 8.11.3 2 | 8.11.4 3 | 8.11.5 4 | 8.11.6 5 | 8.12.0 6 | 8.13.0 7 | -------------------------------------------------------------------------------- /src/instrumentations/pg/tested_versions/20/pg: -------------------------------------------------------------------------------- 1 | 8.11.3 2 | 8.11.4 3 | 8.11.5 4 | 8.11.6 5 | 8.12.0 6 | 8.13.0 7 | -------------------------------------------------------------------------------- /src/instrumentations/pino/PinoInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { PinoInstrumentation } from '@opentelemetry/instrumentation-pino'; 2 | import { LoggingInstrumentor } from '../instrumentor'; 3 | 4 | export default class LumigoPinoInstrumentation extends LoggingInstrumentor { 5 | getInstrumentedModule(): string { 6 | return 'pino'; 7 | } 8 | 9 | getInstrumentation(): PinoInstrumentation { 10 | return new PinoInstrumentation(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/instrumentations/pino/tested_versions/14/pino: -------------------------------------------------------------------------------- 1 | !9.4.0 2 | -------------------------------------------------------------------------------- /src/instrumentations/pino/tested_versions/16/pino: -------------------------------------------------------------------------------- 1 | !9.4.0 -------------------------------------------------------------------------------- /src/instrumentations/pino/tested_versions/18/pino: -------------------------------------------------------------------------------- 1 | 9.4.0 -------------------------------------------------------------------------------- /src/instrumentations/pino/tested_versions/20/pino: -------------------------------------------------------------------------------- 1 | 9.4.0 -------------------------------------------------------------------------------- /src/instrumentations/prisma/PrismaInstrumentation.test.js: -------------------------------------------------------------------------------- 1 | import LumigoPrismaInstrumentation from './PrismaInstrumentation'; 2 | 3 | describe('LumigoPrismaInstrumentation', () => { 4 | afterEach(() => { 5 | jest.clearAllMocks(); 6 | }); 7 | 8 | let lumigoPrismaInstrumentation = new LumigoPrismaInstrumentation(); 9 | 10 | test('getInstrumentedModule should return "prisma"', () => { 11 | expect(lumigoPrismaInstrumentation.getInstrumentedModule()).toEqual('prisma'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/instrumentations/prisma/PrismaInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { PrismaInstrumentation } from '@prisma/instrumentation'; 2 | import { TracingInstrumentor } from '../instrumentor'; 3 | 4 | export default class LumigoPrismaInstrumentation extends TracingInstrumentor { 5 | getInstrumentedModule(): string { 6 | return 'prisma'; 7 | } 8 | 9 | getInstrumentation(): PrismaInstrumentation { 10 | return new PrismaInstrumentation({ 11 | middleware: true, 12 | }); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/instrumentations/prisma/tested_versions/14/prisma: -------------------------------------------------------------------------------- 1 | 4.2.0 2 | 4.2.1 3 | 4.3.0 4 | 4.3.1 5 | 4.4.0 6 | 4.5.0 7 | 4.6.0 8 | 4.6.1 9 | 4.7.0 10 | 4.7.1 11 | 4.8.0 12 | 4.8.1 13 | 4.9.0 14 | 4.10.0 15 | 4.10.1 16 | 4.11.0 17 | 4.12.0 18 | 4.13.0 19 | 4.14.0 20 | 4.14.1 21 | 4.15.0 22 | 4.16.0 23 | 4.16.1 24 | 4.16.2 25 | 5.0.0 26 | 5.1.0 27 | 5.1.1 28 | 5.2.0 29 | 5.3.0 30 | 5.3.1 31 | 5.4.0 32 | 5.4.1 33 | 5.4.2 34 | 5.5.0 35 | 5.5.1 36 | 5.5.2 37 | 5.6.0 38 | 5.7.0 39 | 5.7.1 40 | 5.8.0 41 | 5.8.1 42 | 5.9.0 43 | 5.9.1 44 | 5.10.0 45 | 5.10.1 46 | 5.10.2 47 | 5.11.0 48 | 5.12.0 49 | 5.12.1 50 | 5.13.0 51 | 5.14.0 52 | 5.15.0 53 | 5.15.1 54 | 5.16.0 55 | 5.16.1 56 | 5.16.2 57 | 5.17.0 58 | 5.18.0 59 | 5.19.0 60 | 5.19.1 61 | 5.20.0 62 | -------------------------------------------------------------------------------- /src/instrumentations/prisma/tested_versions/16/prisma: -------------------------------------------------------------------------------- 1 | 4.2.0 2 | 4.2.1 3 | 4.3.0 4 | 4.3.1 5 | 4.4.0 6 | 4.5.0 7 | 4.6.0 8 | 4.6.1 9 | 4.7.0 10 | 4.7.1 11 | 4.8.0 12 | 4.8.1 13 | 4.9.0 14 | 4.10.0 15 | 4.10.1 16 | 4.11.0 17 | 4.12.0 18 | 4.13.0 19 | 4.14.0 20 | 4.14.1 21 | 4.15.0 22 | 4.16.0 23 | 4.16.1 24 | 4.16.2 25 | 5.0.0 26 | 5.1.0 27 | 5.1.1 28 | 5.2.0 29 | 5.3.0 30 | 5.3.1 31 | 5.4.0 32 | 5.4.1 33 | 5.4.2 34 | 5.5.0 35 | 5.5.1 36 | 5.5.2 37 | 5.6.0 38 | 5.7.0 39 | 5.7.1 40 | 5.8.0 41 | 5.8.1 42 | 5.9.0 43 | 5.9.1 44 | 5.10.0 45 | 5.10.1 46 | 5.10.2 47 | 5.11.0 48 | 5.12.0 49 | 5.12.1 50 | 5.13.0 51 | 5.14.0 52 | 5.15.0 53 | 5.15.1 54 | 5.16.0 55 | 5.16.1 56 | 5.16.2 57 | 5.17.0 58 | 5.18.0 59 | 5.19.0 60 | 5.19.1 61 | 5.20.0 62 | -------------------------------------------------------------------------------- /src/instrumentations/prisma/tested_versions/18/prisma: -------------------------------------------------------------------------------- 1 | 4.2.0 2 | 4.2.1 3 | 4.3.0 4 | 4.3.1 5 | 4.4.0 6 | 4.5.0 7 | 4.6.0 8 | 4.6.1 9 | 4.7.0 10 | 4.7.1 11 | 4.8.0 12 | 4.8.1 13 | 4.9.0 14 | 4.10.0 15 | 4.10.1 16 | 4.11.0 17 | 4.12.0 18 | 4.13.0 19 | 4.14.0 20 | 4.14.1 21 | 4.15.0 22 | 4.16.0 23 | 4.16.1 24 | 4.16.2 25 | 5.0.0 26 | 5.1.0 27 | 5.1.1 28 | 5.2.0 29 | 5.3.0 30 | 5.3.1 31 | 5.4.0 32 | 5.4.1 33 | 5.4.2 34 | 5.5.0 35 | 5.5.1 36 | 5.5.2 37 | 5.6.0 38 | 5.7.0 39 | 5.7.1 40 | 5.8.0 41 | 5.8.1 42 | 5.9.0 43 | 5.9.1 44 | 5.10.2 45 | 5.11.0 46 | 5.12.0 47 | 5.12.1 48 | 5.13.0 49 | 5.14.0 50 | 5.15.0 51 | 5.15.1 52 | 5.16.0 53 | 5.16.1 54 | 5.16.2 55 | 5.17.0 56 | 5.18.0 57 | 5.19.0 58 | 5.19.1 59 | 5.20.0 60 | -------------------------------------------------------------------------------- /src/instrumentations/prisma/tested_versions/20/prisma: -------------------------------------------------------------------------------- 1 | 4.2.0 2 | 4.2.1 3 | 4.3.0 4 | 4.3.1 5 | 4.4.0 6 | 4.5.0 7 | 4.6.0 8 | 4.6.1 9 | 4.7.0 10 | 4.7.1 11 | 4.8.0 12 | 4.8.1 13 | 4.9.0 14 | 4.10.0 15 | 4.10.1 16 | 4.11.0 17 | 4.12.0 18 | 4.13.0 19 | 4.14.0 20 | 4.14.1 21 | 4.15.0 22 | 4.16.0 23 | 4.16.1 24 | 4.16.2 25 | 5.0.0 26 | 5.1.0 27 | 5.1.1 28 | 5.2.0 29 | 5.3.0 30 | 5.3.1 31 | 5.4.0 32 | 5.4.1 33 | 5.4.2 34 | 5.5.0 35 | 5.5.1 36 | 5.5.2 37 | 5.6.0 38 | 5.7.0 39 | 5.7.1 40 | 5.8.0 41 | 5.8.1 42 | 5.9.0 43 | 5.9.1 44 | 5.10.0 45 | 5.10.1 46 | 5.10.2 47 | 5.11.0 48 | 5.12.0 49 | 5.12.1 50 | 5.13.0 51 | 5.14.0 52 | 5.15.0 53 | 5.15.1 54 | 5.16.0 55 | 5.16.1 56 | 5.16.2 57 | 5.17.0 58 | 5.18.0 59 | 5.19.0 60 | 5.19.1 61 | 5.20.0 62 | -------------------------------------------------------------------------------- /src/instrumentations/redis/RedisInstrumentation.test.js: -------------------------------------------------------------------------------- 1 | import LumigoRedisInstrumentation from './RedisInstrumentation'; 2 | import child_process from 'child_process'; 3 | 4 | describe('LumigoRedisInstrumentation', () => { 5 | const oldEnv = Object.assign({}, process.env); 6 | beforeEach(() => { 7 | process.env = { ...oldEnv }; 8 | }); 9 | 10 | afterEach(() => { 11 | jest.clearAllMocks(); 12 | process.env = { ...oldEnv }; 13 | }); 14 | 15 | let lumigoRedisInstrumentation = new LumigoRedisInstrumentation(); 16 | 17 | test('disable redis instrumentation', () => { 18 | const child_process = require('child_process'); 19 | child_process.execSync('npm install redis@4.0.0', { stdio: 'inherit' }); 20 | 21 | process.env.LUMIGO_DISABLE_REDIS_INSTRUMENTATION = 'true'; 22 | expect(lumigoRedisInstrumentation.isApplicable()).toEqual(false); 23 | }); 24 | 25 | test('getInstrumentedModule should return "redis and be applicable"', () => { 26 | expect(lumigoRedisInstrumentation.getInstrumentedModule()).toEqual('redis'); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/instrumentations/redis/RedisInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { CommonUtils, ScrubContext } from '@lumigo/node-core'; 2 | import type { Span } from '@opentelemetry/api'; 3 | import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis-4'; 4 | import { getSpanAttributeMaxLength } from '../../utils'; 5 | import { TracingInstrumentor } from '../instrumentor'; 6 | 7 | export default class LumigoRedisInstrumentation extends TracingInstrumentor { 8 | override isApplicable(): boolean { 9 | return ( 10 | super.isApplicable() && 11 | process.env.LUMIGO_DISABLE_REDIS_INSTRUMENTATION?.toLocaleLowerCase() !== 'true' 12 | ); 13 | } 14 | 15 | getInstrumentedModule(): string { 16 | return 'redis'; 17 | } 18 | 19 | getInstrumentation(): RedisInstrumentation { 20 | return new RedisInstrumentation({ 21 | dbStatementSerializer: function (cmdName, cmdArgs) { 22 | const statement = [cmdName, ...cmdArgs].join(' '); 23 | return CommonUtils.payloadStringify( 24 | statement, 25 | ScrubContext.HTTP_REQUEST_BODY, 26 | getSpanAttributeMaxLength() 27 | ); 28 | }, 29 | responseHook: ( 30 | span: Span, 31 | cmdName: string, 32 | cmdArgs: (string | Buffer)[], 33 | response: unknown 34 | ) => { 35 | span.setAttribute( 36 | `db.response.body`, 37 | CommonUtils.payloadStringify( 38 | response, 39 | ScrubContext.HTTP_RESPONSE_BODY, 40 | getSpanAttributeMaxLength() 41 | ) 42 | ); 43 | }, 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/instrumentations/redis/tested_versions/14/redis: -------------------------------------------------------------------------------- 1 | 4.0.0 2 | 4.0.1 3 | 4.0.2 4 | 4.0.3 5 | 4.0.4 6 | 4.0.5 7 | 4.0.6 8 | 4.1.0 9 | 4.1.1 10 | 4.2.0 11 | 4.3.0 12 | 4.3.1 13 | 4.4.0 14 | 4.5.0 15 | 4.5.1 16 | 4.6.0 17 | 4.6.1 18 | 4.6.2 19 | 4.6.3 20 | 4.6.4 21 | 4.6.5 22 | 4.6.6 23 | 4.6.7 24 | 4.6.8 25 | !4.6.9 26 | 4.6.10 27 | 4.6.11 28 | 4.6.12 29 | 4.6.13 30 | 4.6.14 31 | 4.6.15 32 | 4.7.0 33 | -------------------------------------------------------------------------------- /src/instrumentations/redis/tested_versions/16/redis: -------------------------------------------------------------------------------- 1 | 4.0.0 2 | 4.0.1 3 | 4.0.2 4 | 4.0.3 5 | 4.0.4 6 | 4.0.5 7 | 4.0.6 8 | 4.1.0 9 | 4.1.1 10 | 4.2.0 11 | 4.3.0 12 | 4.3.1 13 | 4.4.0 14 | 4.5.0 15 | 4.5.1 16 | 4.6.0 17 | 4.6.1 18 | 4.6.2 19 | 4.6.3 20 | 4.6.4 21 | 4.6.5 22 | 4.6.6 23 | 4.6.7 24 | 4.6.8 25 | 4.6.9 26 | 4.6.10 27 | 4.6.11 28 | 4.6.12 29 | 4.6.13 30 | 4.6.14 31 | 4.6.15 32 | 4.7.0 33 | -------------------------------------------------------------------------------- /src/instrumentations/redis/tested_versions/18/redis: -------------------------------------------------------------------------------- 1 | 4.0.0 2 | 4.0.1 3 | 4.0.2 4 | 4.0.3 5 | 4.0.4 6 | 4.0.5 7 | 4.0.6 8 | 4.1.0 9 | 4.1.1 10 | 4.2.0 11 | 4.3.0 12 | 4.3.1 13 | 4.4.0 14 | 4.5.0 15 | 4.5.1 16 | 4.6.0 17 | 4.6.1 18 | 4.6.2 19 | 4.6.3 20 | 4.6.4 21 | 4.6.5 22 | 4.6.6 23 | 4.6.7 24 | 4.6.8 25 | 4.6.9 26 | 4.6.10 27 | 4.6.11 28 | 4.6.12 29 | 4.6.13 30 | 4.6.14 31 | 4.6.15 32 | 4.7.0 33 | -------------------------------------------------------------------------------- /src/instrumentations/redis/tested_versions/20/redis: -------------------------------------------------------------------------------- 1 | 4.0.0 2 | 4.0.1 3 | 4.0.2 4 | 4.0.3 5 | 4.0.4 6 | 4.0.5 7 | 4.0.6 8 | 4.1.0 9 | 4.1.1 10 | 4.2.0 11 | 4.3.0 12 | 4.3.1 13 | 4.4.0 14 | 4.5.0 15 | 4.5.1 16 | 4.6.0 17 | 4.6.1 18 | 4.6.2 19 | 4.6.3 20 | 4.6.4 21 | 4.6.5 22 | 4.6.6 23 | 4.6.7 24 | 4.6.8 25 | 4.6.9 26 | 4.6.10 27 | 4.6.11 28 | 4.6.12 29 | 4.6.13 30 | 4.6.14 31 | 4.6.15 32 | 4.7.0 33 | -------------------------------------------------------------------------------- /src/instrumentations/winston/WinstonInstrumentation.ts: -------------------------------------------------------------------------------- 1 | import { WinstonInstrumentation } from '@opentelemetry/instrumentation-winston'; 2 | import { LoggingInstrumentor } from '../instrumentor'; 3 | 4 | export default class LumigoWinstonInstrumentation extends LoggingInstrumentor { 5 | getInstrumentedModule(): string { 6 | return 'winston'; 7 | } 8 | 9 | getInstrumentation(): WinstonInstrumentation { 10 | return new WinstonInstrumentation(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/instrumentations/winston/tested_versions/14/winston: -------------------------------------------------------------------------------- 1 | 3.13.0 2 | 3.13.1 3 | 3.14.0 4 | 3.14.1 5 | 3.14.2 6 | 3.15.0 7 | -------------------------------------------------------------------------------- /src/instrumentations/winston/tested_versions/16/winston: -------------------------------------------------------------------------------- 1 | 3.13.0 2 | 3.13.1 3 | 3.14.0 4 | 3.14.1 5 | 3.14.2 6 | 3.15.0 7 | -------------------------------------------------------------------------------- /src/instrumentations/winston/tested_versions/18/winston: -------------------------------------------------------------------------------- 1 | 3.13.0 2 | 3.13.1 3 | 3.14.0 4 | 3.14.1 5 | 3.14.2 6 | 3.15.0 7 | -------------------------------------------------------------------------------- /src/instrumentations/winston/tested_versions/20/winston: -------------------------------------------------------------------------------- 1 | 3.13.0 2 | 3.13.1 3 | 3.14.0 4 | 3.14.1 5 | 3.14.2 6 | 3.15.0 7 | -------------------------------------------------------------------------------- /src/logging.ts: -------------------------------------------------------------------------------- 1 | import { diag, DiagLogLevel, DiagConsoleLogger } from '@opentelemetry/api'; 2 | import { LUMIGO_LOGGING_NAMESPACE } from './constants'; 3 | 4 | declare global { 5 | // eslint-disable-next-line @typescript-eslint/no-namespace 6 | namespace NodeJS { 7 | interface ProcessEnv { 8 | LUMIGO_DEBUG?: string; 9 | } 10 | } 11 | } 12 | 13 | export const logger = diag.createComponentLogger({ 14 | namespace: LUMIGO_LOGGING_NAMESPACE, 15 | }); 16 | 17 | diag.setLogger(new DiagConsoleLogger(), { 18 | logLevel: 19 | process.env.LUMIGO_DEBUG?.toLowerCase() === 'true' ? DiagLogLevel.DEBUG : DiagLogLevel.INFO, 20 | suppressOverrideMessage: true, // Suppress noise in logs 21 | }); 22 | -------------------------------------------------------------------------------- /src/processors/LumigoLogRecordProcessor.test.ts: -------------------------------------------------------------------------------- 1 | import { LogRecord } from '@opentelemetry/sdk-logs'; 2 | import { LumigoLogRecordProcessor } from './LumigoLogRecordProcessor'; 3 | import { LogAttributes, LogBody } from '@opentelemetry/api-logs'; 4 | 5 | import 'jest-json'; 6 | 7 | describe('LumigoLogRecordProcessor', () => { 8 | it('does not fail on missing attributes', () => { 9 | const logRecord: LogRecord = logRecordWith('some body', undefined); 10 | 11 | // @ts-ignore 12 | delete logRecord.attributes; 13 | 14 | const processor = new LumigoLogRecordProcessor(); 15 | processor.onEmit(logRecord); 16 | 17 | expect(logRecord.body).toEqual('some body'); 18 | expect(logRecord.attributes).toBeUndefined(); 19 | }); 20 | 21 | it('scrubs the log body and attributes when those are objects', () => { 22 | jest.isolateModules(() => { 23 | process.env.LUMIGO_SECRET_MASKING_REGEX = '[".*sekret.*"]'; 24 | const { LumigoLogRecordProcessor } = jest.requireActual('./LumigoLogRecordProcessor'); 25 | 26 | const logRecord: LogRecord = logRecordWith( 27 | { 'sekret-body': '123' }, 28 | { 'sekret-attr': '456' } 29 | ); 30 | 31 | const processor = new LumigoLogRecordProcessor(); 32 | processor.onEmit(logRecord); 33 | 34 | expect(logRecord.body).toMatchObject({ 'sekret-body': '****' }); 35 | expect(logRecord.attributes).toMatchObject({ 'sekret-attr': '****' }); 36 | }); 37 | }); 38 | 39 | const logRecordWith = (body: LogBody, attributes: LogAttributes = {}) => 40 | // @ts-ignore 41 | new LogRecord({ logRecordLimits: {} }, { name: 'test', version: 'v1' }, { body, attributes }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/processors/LumigoLogRecordProcessor.ts: -------------------------------------------------------------------------------- 1 | import { scrub } from '@lumigo/node-core'; 2 | import type { Context } from '@opentelemetry/api'; 3 | import type { LogRecord, LogRecordProcessor } from '@opentelemetry/sdk-logs'; 4 | 5 | export class LumigoLogRecordProcessor implements LogRecordProcessor { 6 | forceFlush(): Promise { 7 | return Promise.resolve(); 8 | } 9 | 10 | /* eslint-disable @typescript-eslint/no-unused-vars */ 11 | onEmit(logRecord: LogRecord, context?: Context): void { 12 | logRecord.body = scrub(logRecord.body); 13 | 14 | // @ts-ignore 15 | logRecord.attributes = scrub(logRecord.attributes); 16 | } 17 | 18 | shutdown(): Promise { 19 | return Promise.resolve(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/propagator/w3cTraceContextPropagator.ts: -------------------------------------------------------------------------------- 1 | import { diag, Context, TextMapSetter } from '@opentelemetry/api'; 2 | import { W3CTraceContextPropagator } from '@opentelemetry/core'; 3 | 4 | /* 5 | * List of keys in the carrier that signal the need not to inject 6 | * traceparent/tracestate headers, e.g., when the outgoing request 7 | * is signed with a digest, abnd us adding HTTP headers would 8 | * invalidate the signature. 9 | */ 10 | const contextKeysSkipInject = [ 11 | 'x-amz-content-sha256', // Amazon Sigv4, see https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html 12 | ]; 13 | 14 | export class LumigoW3CTraceContextPropagator extends W3CTraceContextPropagator { 15 | override inject(context: Context, carrier: unknown, setter: TextMapSetter): void { 16 | if (typeof carrier === 'object') { 17 | const carrierKeys = Object.keys(carrier).map((key) => key.toLowerCase()); 18 | const carrierFilteredKeys = carrierKeys.filter((key) => contextKeysSkipInject.includes(key)); 19 | 20 | if (carrierFilteredKeys.length) { 21 | diag.debug( 22 | `Skipping injection of trace context due to keys in carrier: ${carrierFilteredKeys.join( 23 | ', ' 24 | )}` 25 | ); 26 | return; 27 | } 28 | } 29 | 30 | super.inject(context, carrier, setter); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/requireUtils.test.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { safeRequire } from './requireUtils'; 3 | import { version } from '../package.json'; 4 | 5 | describe('safeRequire', () => { 6 | afterEach(() => { 7 | jest.clearAllMocks(); 8 | }); 9 | 10 | test('requires an existing module with the given path', () => { 11 | const packageJsonPath = path.join(__dirname, '..', 'package.json'); 12 | 13 | const result = safeRequire(packageJsonPath); 14 | 15 | expect(result.version).toEqual(version); 16 | }); 17 | 18 | test('does not fail but returns undefined for a non-existing module', () => { 19 | const result = safeRequire('BlaBlaBlaBla'); 20 | 21 | expect(result).toBeUndefined(); 22 | }); 23 | 24 | test('does not fail but returns undefined when an errors occurs when loading the module', () => { 25 | jest.doMock('fs', () => { 26 | throw Error('RandomError'); 27 | }); 28 | 29 | const result = safeRequire('fs'); 30 | 31 | expect(result).toBeUndefined(); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/requireUtils.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { logger } from './logging'; 3 | 4 | const getRequireFunction = (): NodeRequire => 5 | // @ts-ignore __non_webpack_require__ not available at compile time 6 | typeof __non_webpack_require__ !== 'undefined' ? __non_webpack_require__ : require; 7 | 8 | export const safeRequire = (moduleSpecifier) => { 9 | try { 10 | const customRequire = getRequireFunction(); 11 | const resolvedPath = safeResolvePath(moduleSpecifier); 12 | return resolvedPath ? customRequire(resolvedPath) : undefined; 13 | } catch (e) { 14 | logger.warn('Unable to load module', { 15 | error: e, 16 | libId: moduleSpecifier, 17 | }); 18 | 19 | return undefined; 20 | } 21 | }; 22 | 23 | const tryResolveFromPathGroup = ( 24 | customRequire: NodeRequire, 25 | moduleSpecifier: string, 26 | paths: string[] 27 | ): string => { 28 | try { 29 | const resolvedPath = customRequire.resolve(moduleSpecifier, { paths }); 30 | if (resolvedPath) { 31 | logger.debug( 32 | `${moduleSpecifier} successfully loaded from ${resolvedPath}. Paths searched: `, 33 | paths 34 | ); 35 | } else { 36 | logger.debug( 37 | `${moduleSpecifier} could not be loaded from any of the following paths: `, 38 | paths 39 | ); 40 | } 41 | return resolvedPath; 42 | } catch (error) { 43 | if (error.code !== 'MODULE_NOT_FOUND') { 44 | logger.warn('Unable to resolve module', { error, moduleSpecifier }); 45 | return undefined; 46 | } 47 | } 48 | }; 49 | 50 | const safeResolvePath = (moduleSpecifier: string): string | undefined => { 51 | const customReq = getRequireFunction(); 52 | 53 | const pathGroups = [ 54 | // default paths - same as not specifying paths to require.resolve() 55 | customReq.resolve?.paths?.(moduleSpecifier) || [], 56 | // paths specified in NODE_PATH, in case the user has set it for some reason 57 | (process.env.NODE_PATH || '').split(':'), 58 | // process CWD - i.e. the node_nodules folder of the process require()-ed the distro 59 | [path.resolve(process.cwd(), 'node_modules')], 60 | ]; 61 | 62 | return pathGroups 63 | .map((pathGroup) => tryResolveFromPathGroup(customReq, moduleSpecifier, pathGroup)) 64 | .find(Boolean); 65 | }; 66 | 67 | export const canRequireModule = (moduleSpecifier) => !!safeResolvePath(moduleSpecifier); 68 | -------------------------------------------------------------------------------- /src/resources/detectors/LumigoContainerNameDetector.test.ts: -------------------------------------------------------------------------------- 1 | import { LumigoContainerNameDetector } from './LumigoContainerNameDetector'; 2 | import mock from 'mock-fs'; 3 | 4 | describe('LumigoContainerNameDetector', () => { 5 | const OLD_ENV = process.env; 6 | 7 | beforeEach(() => { 8 | process.env = { ...OLD_ENV }; // Make a copy of env so that we can alter it in tests 9 | }); 10 | 11 | afterEach(() => { 12 | process.env = OLD_ENV; // Restore old environment 13 | jest.resetAllMocks(); 14 | }); 15 | 16 | describe('lumigo container name is detected correctly', () => { 17 | beforeEach(() => { 18 | process.env.LUMIGO_CONTAINER_NAME = 'some_container_name'; 19 | }); 20 | 21 | it('detects resource attributes correctly', async () => { 22 | const resource = await new LumigoContainerNameDetector().detect(); 23 | expect(resource.attributes).toEqual({ 24 | 'k8s.container.name': 'some_container_name', 25 | }); 26 | }); 27 | }); 28 | 29 | describe('no container name found', () => { 30 | it('detects resource attributes correctly', async () => { 31 | const resource = await new LumigoContainerNameDetector().detect(); 32 | expect(resource.attributes).not.toHaveProperty('k8s.container.name'); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/resources/detectors/LumigoContainerNameDetector.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | import { Detector, Resource, ResourceDetectionConfig } from '@opentelemetry/resources'; 3 | import { logger } from '../../logging'; 4 | import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; 5 | 6 | export const LUMIGO_CONTAINER_NAME_ENV_VAR = 'LUMIGO_CONTAINER_NAME'; 7 | 8 | /** 9 | * LumigoTagDetector provides resource attributes with lumigo tag 10 | * set by the application in env var 11 | */ 12 | export class LumigoContainerNameDetector implements Detector { 13 | readonly containerName: string | undefined; 14 | 15 | constructor() { 16 | this.containerName = process.env[LUMIGO_CONTAINER_NAME_ENV_VAR]; 17 | } 18 | 19 | async detect(_config?: ResourceDetectionConfig): Promise { 20 | return new Promise((resolve) => { 21 | if (!this.containerName) { 22 | resolve(Resource.empty()); 23 | } else { 24 | resolve( 25 | new Resource({ 26 | [SemanticResourceAttributes.K8S_CONTAINER_NAME]: this.containerName, 27 | }) 28 | ); 29 | } 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/resources/detectors/LumigoDistroDetector.test.ts: -------------------------------------------------------------------------------- 1 | import { LumigoDistroDetector } from './LumigoDistroDetector'; 2 | import mock from 'mock-fs'; 3 | 4 | describe('LumigoDistroDetector', () => { 5 | const OLD_ENV = process.env; 6 | 7 | beforeEach(() => { 8 | process.env = { ...OLD_ENV }; // Make a copy of env so that we can alter it in tests 9 | }); 10 | 11 | afterEach(() => { 12 | process.env = OLD_ENV; // Restore old environment 13 | jest.resetAllMocks(); 14 | }); 15 | 16 | describe('with Task metadata endpoint version 4', () => { 17 | beforeEach(() => { 18 | process.env.ECS_CONTAINER_METADATA_URI_V4 = 'test_url'; 19 | }); 20 | 21 | it('detects resource attributes correctly', async () => { 22 | const resource = await new LumigoDistroDetector('1.0.1').detect(); 23 | expect(resource.attributes).toEqual({ 24 | 'lumigo.distro.version': '1.0.1', 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/resources/detectors/LumigoDistroDetector.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | import { Detector, Resource, ResourceDetectionConfig } from '@opentelemetry/resources'; 3 | 4 | export const LUMIGO_DISTRO_VERSION = 'lumigo.distro.version'; 5 | 6 | /** 7 | * LumigoDistroDetector provides resource attributes documeting which version of the 8 | * Lumigo Distro for OpenTelemetry is used. 9 | */ 10 | export class LumigoDistroDetector implements Detector { 11 | readonly version: string; 12 | 13 | constructor(version = 'unknown') { 14 | this.version = version; 15 | } 16 | 17 | async detect(_config?: ResourceDetectionConfig): Promise { 18 | return new Promise((resolve) => { 19 | resolve( 20 | new Resource({ 21 | [LUMIGO_DISTRO_VERSION]: this.version, 22 | }) 23 | ); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/detectors/LumigoTagDetector.test.ts: -------------------------------------------------------------------------------- 1 | import { LumigoTagDetector } from './LumigoTagDetector'; 2 | import mock from 'mock-fs'; 3 | 4 | describe('LumigoTagDetector', () => { 5 | const OLD_ENV = process.env; 6 | 7 | beforeEach(() => { 8 | process.env = { ...OLD_ENV }; // Make a copy of env so that we can alter it in tests 9 | }); 10 | 11 | afterEach(() => { 12 | process.env = OLD_ENV; // Restore old environment 13 | jest.resetAllMocks(); 14 | }); 15 | 16 | describe('lumigo tag is detected correctly', () => { 17 | beforeEach(() => { 18 | process.env.LUMIGO_TAG = 'some_app_tag'; 19 | }); 20 | 21 | it('detects resource attributes correctly', async () => { 22 | const resource = await new LumigoTagDetector().detect(); 23 | expect(resource.attributes).toEqual({ 24 | 'lumigo.tag': 'some_app_tag', 25 | }); 26 | }); 27 | }); 28 | 29 | describe('lumigo tag with semicolon is ignored', () => { 30 | beforeEach(() => { 31 | process.env.LUMIGO_TAG = 'some_;app_tag'; 32 | }); 33 | 34 | it('detects resource attributes correctly', async () => { 35 | const resource = await new LumigoTagDetector().detect(); 36 | expect(resource.attributes).not.toHaveProperty('lumigo.tag'); 37 | }); 38 | }); 39 | 40 | describe('no lumigo tag found', () => { 41 | it('detects resource attributes correctly', async () => { 42 | const resource = await new LumigoTagDetector().detect(); 43 | expect(resource.attributes).not.toHaveProperty('lumigo.tag'); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/resources/detectors/LumigoTagDetector.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | import { Detector, Resource, ResourceDetectionConfig } from '@opentelemetry/resources'; 3 | import { logger } from '../../logging'; 4 | 5 | export const LUMIGO_TAG_ATTRIBUTE = 'lumigo.tag'; 6 | export const LUMIGO_TAG_ENV_VAR = 'LUMIGO_TAG'; 7 | 8 | /** 9 | * LumigoTagDetector provides resource attributes with lumigo tag 10 | * set by the application in env var 11 | */ 12 | export class LumigoTagDetector implements Detector { 13 | readonly tag: string | undefined; 14 | 15 | constructor() { 16 | this.tag = process.env[LUMIGO_TAG_ENV_VAR]; 17 | } 18 | 19 | async detect(_config?: ResourceDetectionConfig): Promise { 20 | return new Promise((resolve) => { 21 | if (!this.tag) { 22 | resolve(Resource.empty()); 23 | } else if (this.tag.includes(';')) { 24 | logger.warn( 25 | `Lumigo tag contains a semicolon, which is not allowed. The tag will be ignored.`, 26 | { tag: this.tag } 27 | ); 28 | resolve(Resource.empty()); 29 | } else { 30 | resolve( 31 | new Resource({ 32 | [LUMIGO_TAG_ATTRIBUTE]: this.tag, 33 | }) 34 | ); 35 | } 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/resources/detectors/ProcessEnvironmentDetector.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | import { CommonUtils, ScrubContext } from '@lumigo/node-core'; 3 | import { Detector, Resource, ResourceDetectionConfig } from '@opentelemetry/resources'; 4 | import { getResourceAttributeMaxLength } from '../../utils'; 5 | 6 | export class ProcessEnvironmentDetector implements Detector { 7 | detect = async (_config?: ResourceDetectionConfig): Promise => 8 | Promise.resolve( 9 | new Resource({ 10 | 'process.environ': CommonUtils.payloadStringify( 11 | /* 12 | * Stringify a shallow copy, as the OpenTelemetry SDK modifes the object 13 | * in a way that does not play nice with the way we use Symbols in the 14 | * scrubbing process. 15 | */ 16 | { ...process.env }, 17 | ScrubContext.PROCESS_ENVIRONMENT, 18 | getResourceAttributeMaxLength() 19 | ), 20 | }) 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/resources/detectors/index.ts: -------------------------------------------------------------------------------- 1 | export { LumigoDistroDetector } from './LumigoDistroDetector'; 2 | export { LumigoKubernetesDetector } from './LumigoKubernetesDetector'; 3 | export { LumigoTagDetector } from './LumigoTagDetector'; 4 | export { LumigoContainerNameDetector } from './LumigoContainerNameDetector'; 5 | -------------------------------------------------------------------------------- /src/resources/spanProcesser.test.js: -------------------------------------------------------------------------------- 1 | import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; 2 | 3 | import { 4 | LumigoSpanProcessor, 5 | shouldSkipSpanExport, 6 | getSpanSkipExportAttributes, 7 | } from './spanProcessor'; 8 | 9 | describe('span processor', () => { 10 | afterEach(() => { 11 | jest.clearAllMocks(); 12 | }); 13 | 14 | [ 15 | { 16 | attributes: { SKIP_EXPORT: true }, 17 | shouldSkip: true, 18 | }, 19 | { 20 | attributes: { SKIP_EXPORT: false }, 21 | shouldSkip: false, 22 | }, 23 | { 24 | attributes: { SKIP_EXPORT: 'not a boolean' }, 25 | shouldSkip: false, 26 | }, 27 | { 28 | // This is the string "true", not a boolean value 29 | attributes: { SKIP_EXPORT: 'true' }, 30 | shouldSkip: false, 31 | }, 32 | { 33 | attributes: { SKIP_EXPORT: null }, 34 | shouldSkip: false, 35 | }, 36 | { 37 | attributes: { SKIP_EXPORT: undefined }, 38 | shouldSkip: false, 39 | }, 40 | { 41 | attributes: {}, 42 | shouldSkip: false, 43 | }, 44 | ].map(({ attributes, shouldSkip }) => { 45 | test('test should skip span export logic', () => { 46 | const readableSpan = { attributes }; 47 | expect(shouldSkipSpanExport(readableSpan)).toEqual(shouldSkip); 48 | }); 49 | }); 50 | 51 | test('test get span skip export attributes', () => { 52 | expect(getSpanSkipExportAttributes()).toEqual({ SKIP_EXPORT: true }); 53 | expect(getSpanSkipExportAttributes(true)).toEqual({ SKIP_EXPORT: true }); 54 | expect(getSpanSkipExportAttributes(false)).toEqual({ SKIP_EXPORT: false }); 55 | }); 56 | 57 | [true, false].map((mockShouldSkipResult) => { 58 | test('test span processor checks skip attribute', () => { 59 | // Here we mock the parent class `onEnd` function. If the span was skipped this func shouldn't have been called 60 | const spySuperOnEnd = jest.spyOn(BatchSpanProcessor.prototype, 'onEnd').mockImplementation(); 61 | 62 | const processor = new LumigoSpanProcessor(); 63 | 64 | expect(spySuperOnEnd).not.toHaveBeenCalled(); 65 | processor.onEnd({ attributes: { SKIP_EXPORT: mockShouldSkipResult } }); 66 | if (mockShouldSkipResult) { 67 | expect(spySuperOnEnd).not.toHaveBeenCalled(); 68 | } else { 69 | expect(spySuperOnEnd).toHaveBeenCalled(); 70 | } 71 | }); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /src/resources/spanProcessor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BatchSpanProcessor, 3 | ReadableSpan, 4 | Span as MutableSpan, 5 | } from '@opentelemetry/sdk-trace-base'; 6 | import { logger } from '../logging'; 7 | 8 | export class LumigoSpanProcessor extends BatchSpanProcessor { 9 | override onEnd(span: ReadableSpan) { 10 | if (shouldSkipSpanExport(span)) { 11 | logger.debug('Not exporting span because it has SKIP_EXPORT=true attribute'); 12 | return; 13 | } 14 | 15 | super.onEnd(span); 16 | } 17 | } 18 | 19 | /** 20 | * Given a readable span, returns true if the span should be skipped from export 21 | * @param span A readable span to check 22 | */ 23 | export const shouldSkipSpanExport = (span: ReadableSpan): boolean => { 24 | return span.attributes && span.attributes.SKIP_EXPORT === true; 25 | }; 26 | 27 | /** 28 | * Returns the span attributes that need to be added to a span in order for it to be skipped. 29 | * @param skipExport (Default true) should the span be skipped from export. 30 | * you can set it to false in order to explicitly not skip exporting a span 31 | */ 32 | export const getSpanSkipExportAttributes = (skipExport = true) => { 33 | return { 34 | SKIP_EXPORT: skipExport, 35 | }; 36 | }; 37 | 38 | export const setSpanAsNotExportable = (span: MutableSpan) => { 39 | span.setAttributes(getSpanSkipExportAttributes()); 40 | }; 41 | -------------------------------------------------------------------------------- /src/samplers/combinedSampler.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Sampler, 3 | SamplingResult, 4 | SamplingDecision, 5 | ParentBasedSampler, 6 | } from '@opentelemetry/sdk-trace-base'; 7 | import type { Context, Link, Attributes, SpanKind } from '@opentelemetry/api'; 8 | 9 | import { LumigoSampler } from './lumigoSampler'; 10 | import { MongodbSampler } from './mongodbSampler'; 11 | import { RedisSampler } from './redisSampler'; 12 | 13 | export class CombinedSampler implements Sampler { 14 | private samplers: Sampler[]; 15 | 16 | constructor(...samplers: Sampler[]) { 17 | this.samplers = samplers; 18 | } 19 | /* eslint-disable @typescript-eslint/no-unused-vars */ 20 | shouldSample( 21 | context: Context, 22 | traceId: string, 23 | spanName: string, 24 | spanKind: SpanKind, 25 | attributes: Attributes, 26 | links: Link[] 27 | ): SamplingResult { 28 | // Iterate through each sampler 29 | for (const sampler of this.samplers) { 30 | const result = sampler.shouldSample(context, traceId, spanName, spanKind, attributes, links); 31 | 32 | // If any sampler decides NOT_RECORD, we respect that decision 33 | if (result.decision === SamplingDecision.NOT_RECORD) { 34 | return result; 35 | } 36 | } 37 | 38 | // If none decided to NOT_RECORD, we default to RECORD_AND_SAMPLED 39 | return { decision: SamplingDecision.RECORD_AND_SAMPLED }; 40 | } 41 | } 42 | 43 | export const getCombinedSampler = () => { 44 | const lumigoSampler = new LumigoSampler(); 45 | const mongodbSampler = new MongodbSampler(); 46 | const redisSampler = new RedisSampler(); 47 | const combinedSampler = new CombinedSampler(lumigoSampler, mongodbSampler, redisSampler); 48 | 49 | return new ParentBasedSampler({ 50 | root: combinedSampler, 51 | remoteParentSampled: combinedSampler, 52 | localParentSampled: combinedSampler, 53 | }); 54 | }; 55 | -------------------------------------------------------------------------------- /src/spans/types.ts: -------------------------------------------------------------------------------- 1 | export enum AwsOtherService { 2 | ApiGateway, 3 | ExternalService, 4 | ElasticBeanstalkSqsDaemon, 5 | } 6 | 7 | export enum AwsParsedService { 8 | DynamoDB = 'dynamodb', 9 | EventBridge = 'events', 10 | Kinesis = 'kinesis', 11 | Lambda = 'lambda', 12 | SNS = 'sns', 13 | SQS = 'sqs', 14 | } 15 | 16 | export type SupportedAwsServices = AwsParsedService | AwsOtherService; 17 | -------------------------------------------------------------------------------- /src/supportedVersions.json: -------------------------------------------------------------------------------- 1 | { 2 | "minMajor": 14, 3 | "maxMajor": 20 4 | } -------------------------------------------------------------------------------- /src/test/integration/@grpc/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/@grpc/tested_versions -------------------------------------------------------------------------------- /src/test/integration/@nestjs/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/@nestjs/tested_versions -------------------------------------------------------------------------------- /src/test/integration/amqplib/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/amqplib/tested_versions -------------------------------------------------------------------------------- /src/test/integration/express/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/express/tested_versions -------------------------------------------------------------------------------- /src/test/integration/fastify/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/fastify/tested_versions -------------------------------------------------------------------------------- /src/test/integration/ioredis/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/ioredis/tested_versions -------------------------------------------------------------------------------- /src/test/integration/kafkajs/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/kafkajs/tested_versions -------------------------------------------------------------------------------- /src/test/integration/mongodb/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/mongodb/tested_versions -------------------------------------------------------------------------------- /src/test/integration/next/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/next/tested_versions -------------------------------------------------------------------------------- /src/test/integration/pg/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/pg/tested_versions -------------------------------------------------------------------------------- /src/test/integration/prisma/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/prisma/tested_versions -------------------------------------------------------------------------------- /src/test/integration/redis/tested_versions: -------------------------------------------------------------------------------- 1 | ../../../../src/instrumentations/redis/tested_versions -------------------------------------------------------------------------------- /src/tools/httpUtils.js: -------------------------------------------------------------------------------- 1 | import { isEncodingType, safeExecute } from '../utils'; 2 | 3 | export const isValidHttpRequestBody = (reqBody) => 4 | !!(reqBody && (typeof reqBody === 'string' || reqBody instanceof Buffer)); 5 | 6 | export const extractBodyFromEmitSocketEvent = (socketEventArgs) => { 7 | return safeExecute(() => { 8 | if (socketEventArgs && socketEventArgs._httpMessage && socketEventArgs._httpMessage._hasBody) { 9 | const httpMessage = socketEventArgs._httpMessage; 10 | let lines = []; 11 | if (httpMessage.hasOwnProperty('outputData')) { 12 | lines = httpMessage.outputData?.[0]?.data?.split('\n'); 13 | } else if (httpMessage.hasOwnProperty('output')) { 14 | lines = httpMessage.output?.[0]?.split('\n'); 15 | } 16 | if (lines.length > 0) { 17 | return lines[lines.length - 1]; 18 | } 19 | } 20 | })(); 21 | }; 22 | 23 | export const extractBodyFromWriteOrEndFunc = (writeEventArgs) => { 24 | return safeExecute(() => { 25 | if (isValidHttpRequestBody(writeEventArgs[0])) { 26 | const encoding = isEncodingType(writeEventArgs[1]) ? writeEventArgs[1] : 'utf8'; 27 | return typeof writeEventArgs[0] === 'string' 28 | ? Buffer.from(writeEventArgs[0]).toString(encoding) 29 | : writeEventArgs[0].toString(); 30 | } 31 | })(); 32 | }; 33 | 34 | /** 35 | * Formats a raw url string by: 36 | * * removing empty path "/" path - "https://example.com/" -> "https://example.com" 37 | * * removing port if not standard - "https://example.com:443" -> "https://example.com" 38 | * @param raw_url 39 | * @returns string formatted url 40 | */ 41 | export const standardizeHttpUrl = (raw_url) => { 42 | const parsedUrl = new URL(raw_url); 43 | const path = parsedUrl.pathname && parsedUrl.pathname !== '/' ? parsedUrl.pathname : ''; 44 | return `${parsedUrl.protocol}//${parsedUrl.host}${path}${parsedUrl.search}`; 45 | }; 46 | -------------------------------------------------------------------------------- /src/tools/jsonSortify.ts: -------------------------------------------------------------------------------- 1 | //Copied from https://github.com/ThomasR/JSON.sortify/blob/master/src/index.js 2 | //Because its not TS compatible 3 | 4 | const sortKeys = (o) => { 5 | if (Array.isArray(o)) { 6 | return o.map(sortKeys); 7 | } 8 | if (o instanceof Object) { 9 | // put numeric keys first 10 | let numeric = []; 11 | let nonNumeric = []; 12 | Object.keys(o).forEach((key) => { 13 | if (/^(0|[1-9][0-9]*)$/.test(key)) { 14 | numeric.push(+key); 15 | } else { 16 | nonNumeric.push(key); 17 | } 18 | }); 19 | // do the rearrangement 20 | return numeric 21 | .sort((a, b) => a - b) 22 | .concat(nonNumeric.sort()) 23 | .reduce((result, key) => { 24 | result[key] = sortKeys(o[key]); // recurse! 25 | return result; 26 | }, {}); 27 | } 28 | return o; 29 | }; 30 | 31 | const jsonStringify = JSON.stringify.bind(JSON); // this allows redefinition like JSON.stringify = require('json.sortify') 32 | 33 | export const sortify = (value, replacer?, space?) => { 34 | // replacer, toJSON(), cyclic references and other stuff is better handled by native stringifier. 35 | // So we do JSON.stringify(sortKeys( JSON.parse(JSON.stringify()) )). 36 | // This approach is slightly slower but much safer than a manual stringification. 37 | let nativeJson = jsonStringify(value, replacer, 0); 38 | if (!nativeJson || (nativeJson[0] !== '{' && nativeJson[0] !== '[')) { 39 | // if value is not an Object or Array 40 | return nativeJson; 41 | } 42 | let cleanObj = JSON.parse(nativeJson); 43 | return jsonStringify(sortKeys(cleanObj), null, space); 44 | }; 45 | -------------------------------------------------------------------------------- /src/utils.test.ts: -------------------------------------------------------------------------------- 1 | import { getSpanAttributeMaxLength, safeParse } from './utils'; 2 | 3 | describe('getSpanAttributeMaxLength', () => { 4 | describe('value according to env. vars', () => { 5 | beforeEach(() => { 6 | jest.resetModules(); 7 | process.env.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = undefined; 8 | process.env.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = undefined; 9 | }); 10 | 11 | it('when OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT is set', () => { 12 | process.env.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = '1'; 13 | const size = getSpanAttributeMaxLength(); 14 | expect(size).toEqual(1); 15 | }); 16 | 17 | it('when OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT is set', () => { 18 | process.env.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = '50'; 19 | const size = getSpanAttributeMaxLength(); 20 | expect(size).toEqual(50); 21 | }); 22 | 23 | it('when OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT and OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT are set', () => { 24 | process.env.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = '1'; 25 | process.env.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = '50'; 26 | const size = getSpanAttributeMaxLength(); 27 | expect(size).toEqual(1); 28 | }); 29 | 30 | it('when no env. vars are set, get default value', () => { 31 | const size = getSpanAttributeMaxLength(); 32 | expect(size).toEqual(2048); 33 | }); 34 | 35 | it('when OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT is set to NaN will return default value', () => { 36 | process.env.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = 'a'; 37 | const size = getSpanAttributeMaxLength(); 38 | expect(size).toEqual(2048); 39 | }); 40 | }); 41 | }); 42 | 43 | describe('safeParse', () => { 44 | it('should return the parsed object', () => { 45 | const obj = { a: 1, b: 2 }; 46 | expect(safeParse(JSON.stringify(obj))).toEqual(obj); 47 | }); 48 | 49 | it('should return the same string', () => { 50 | const str = 'test'; 51 | expect(safeParse(str)).toEqual(str); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /test/fixtures/dummy-module/index.js: -------------------------------------------------------------------------------- 1 | module.exports = "dummy!" -------------------------------------------------------------------------------- /test/helpers/InstrumentationsVersionManager.ts: -------------------------------------------------------------------------------- 1 | export type InstrumentationsVersions = { 2 | [key: string]: { 3 | supported: string[] 4 | unsupported: string[] 5 | } 6 | } 7 | 8 | class InstrumentationsVersionsManager { 9 | private instrumentationsVersions: InstrumentationsVersions = {}; 10 | 11 | addPackageSupportedVersion(packageName: string, version: string) { 12 | if (!this.instrumentationsVersions[packageName]) { 13 | this.instrumentationsVersions[packageName] = {supported: [version], unsupported: []}; 14 | } else { 15 | // only add version to supported if it was not added anywhere else before 16 | if (!this.instrumentationsVersions[packageName].unsupported.includes(version) && 17 | !this.instrumentationsVersions[packageName].supported.includes(version)) { 18 | this.instrumentationsVersions[packageName].supported.push(version); 19 | } 20 | } 21 | } 22 | 23 | addPackageUnsupportedVersion(packageName: string, version: string) { 24 | if (!this.instrumentationsVersions[packageName]) { 25 | this.instrumentationsVersions[packageName] = {supported: [], unsupported: [version]}; 26 | } else { 27 | if (!this.instrumentationsVersions[packageName].unsupported.includes(version)) { 28 | this.instrumentationsVersions[packageName].unsupported.push(version); 29 | } 30 | // remove version from supported if it was added before 31 | this.instrumentationsVersions[packageName].supported = this.instrumentationsVersions[packageName].supported.filter( 32 | (supportedVersion) => supportedVersion !== version 33 | ); 34 | } 35 | } 36 | 37 | getInstrumentationsVersions(): InstrumentationsVersions { 38 | return this.instrumentationsVersions; 39 | } 40 | 41 | clear() { 42 | this.instrumentationsVersions = {} 43 | } 44 | } 45 | 46 | export const instrumentationsVersionManager = new InstrumentationsVersionsManager() 47 | -------------------------------------------------------------------------------- /test/instrumentations/@aws-sdk/client-sqs/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/@aws-sdk/client-sqs/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/@aws-sdk/client-sqs/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-aws-sdk-client-sqs-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry aws-sdk-client-sqs-app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@aws-sdk/client-sqs": "^3.525.0", 12 | "@lumigo/opentelemetry": "file:../../../../../distro.tgz" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/amqplib/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/amqplib/amqplibTestUtils.js: -------------------------------------------------------------------------------- 1 | import { SpanKind, SpanStatusCode } from '@opentelemetry/api'; 2 | 3 | export function getExpectedResourceAttributes() { 4 | return { 5 | 'service.name': 'amqplib', 6 | 'telemetry.sdk.language': 'nodejs', 7 | 'telemetry.sdk.name': 'opentelemetry', 8 | 'telemetry.sdk.version': expect.any(String), 9 | 'framework': expect.toBeOneOf(['node', 'express']), 10 | 'process.environ': expect.any(String), 11 | 'lumigo.distro.version': expect.stringMatching(/1\.\d+\.\d+/), 12 | 'process.pid': expect.any(Number), 13 | 'process.executable.name': 'node', 14 | 'process.runtime.description': 'Node.js', 15 | 'process.runtime.name': 'nodejs', 16 | 'process.runtime.version': expect.stringMatching(/\d+\.\d+\.\d+/), 17 | }; 18 | } 19 | 20 | export function getExpectedSpan({ 21 | nameSpanAttr, 22 | spanKind, 23 | resourceAttributes, 24 | host, 25 | topic, 26 | message, 27 | }) { 28 | let messageKey; 29 | switch (spanKind) { 30 | case SpanKind.PRODUCER: 31 | messageKey = 'messaging.publish.body'; 32 | break; 33 | case SpanKind.CONSUMER: 34 | messageKey = 'messaging.consume.body'; 35 | break; 36 | default: 37 | throw new Error('spanKind must be either SpanKind.PRODUCER or SpanKind.CONSUMER'); 38 | } 39 | return { 40 | traceId: expect.any(String), 41 | id: expect.any(String), 42 | timestamp: expect.any(Number), 43 | duration: expect.any(Number), 44 | name: nameSpanAttr, 45 | kind: spanKind, 46 | resource: { 47 | attributes: resourceAttributes, 48 | }, 49 | attributes: { 50 | 'messaging.destination': '', 51 | 'messaging.destination_kind': 'topic', 52 | 'messaging.protocol': 'AMQP', 53 | 'messaging.protocol_version': '0.9.1', 54 | 'messaging.rabbitmq.routing_key': topic, 55 | [messageKey]: JSON.stringify(message), 56 | 'messaging.system': 'rabbitmq', 57 | // the port is reported inconsistently, ignore it 58 | 'messaging.url': expect.stringContaining(`amqp://${host}:`), 59 | 'net.peer.name': host, 60 | 'net.peer.port': expect.any(Number), 61 | }, 62 | status: { 63 | code: SpanStatusCode.UNSET, 64 | }, 65 | events: [], 66 | }; 67 | } 68 | 69 | export function filterAmqplibSpans(spans, topic) { 70 | return spans.filter((span) => span.name.includes(topic)); 71 | } 72 | -------------------------------------------------------------------------------- /test/instrumentations/amqplib/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/amqplib/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-amqplib-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry amqplib_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "amqplib": "^0.10.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/aws-sdk/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/aws-sdk/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/aws-sdk/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-aws-sdk-v2-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry aws-sdk-app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "aws-sdk": "^2.1533.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/bunyan/.gitignore: -------------------------------------------------------------------------------- 1 | logs -------------------------------------------------------------------------------- /test/instrumentations/bunyan/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/bunyan/app/bunyan_app.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const url = require('url'); 3 | const { init } = require("@lumigo/opentelemetry") 4 | 5 | require('log-timestamp'); 6 | 7 | const host = 'localhost'; 8 | let httpServer; 9 | 10 | function respond(res, status, body) { 11 | console.log(`responding with ${status} ${JSON.stringify(body)}`); 12 | res.setHeader('Content-Type', 'application/json'); 13 | res.setHeader('access-control-allow-origin', '*'); 14 | res.writeHead(status); 15 | res.end(JSON.stringify(body)); 16 | } 17 | 18 | const requestListener = async function (req, res) { 19 | await init; 20 | 21 | const bunyan = require('bunyan'); 22 | const bunyanLogger = bunyan.createLogger({ name: __filename }) 23 | 24 | console.error(`Received request: ${req.method} ${req.url}`); 25 | 26 | const requestUrl = url.parse(req.url, true); 27 | 28 | switch (requestUrl.pathname) { 29 | case '/write-log-line': 30 | try { 31 | const logLine = JSON.parse(requestUrl?.query?.logLine) 32 | bunyanLogger.info(logLine); 33 | respond(res, 200, {}) 34 | } catch (err) { 35 | console.error(`Error writing log line`, err); 36 | respond(res, 500, { error: err }); 37 | } 38 | break; 39 | 40 | case '/quit': 41 | console.error('Received quit command'); 42 | respond(res, 200, {}); 43 | httpServer.close(); 44 | break; 45 | 46 | default: 47 | respond(res, 404, { error: 'Resource not found' }); 48 | } 49 | }; 50 | 51 | httpServer = http.createServer(requestListener); 52 | httpServer.listen(0, host, () => { 53 | const port = httpServer.address().port; 54 | console.error(`HTTP server listening on port ${port}`); 55 | if (process.send) { 56 | process.send(port); 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /test/instrumentations/bunyan/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-bunyan-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry bunyan_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "bunyan": "^1.8.15" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/express/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/express/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/express/app/express_app.js: -------------------------------------------------------------------------------- 1 | require('@lumigo/opentelemetry'); 2 | const express = require('express'); 3 | const bodyParser = require('body-parser'); 4 | const app = express(); 5 | require('log-timestamp'); 6 | const axios = require("axios"); 7 | 8 | let server; 9 | 10 | // parse application/x-www-form-urlencoded 11 | app.use(bodyParser.urlencoded({ extended: false })); 12 | 13 | // parse application/json 14 | app.use(bodyParser.json()); 15 | 16 | app.get('/test-scrubbing', async (_, res) => { 17 | res.status(200).send({ 18 | Authorization: 'SECRET', 19 | }); 20 | }); 21 | 22 | app.get('/', async (_, res) => { 23 | res.status(200).send('server is ready'); 24 | }); 25 | 26 | app.get('/basic', async (_, res) => { 27 | res.setHeader('Content-Type', 'text/plain'); 28 | res.status(200).send('Hello world'); 29 | }); 30 | 31 | app.get('/quit', async (_, res) => { 32 | console.error('Received quit command'); 33 | res.status(200).send({}); 34 | server.close(); 35 | }); 36 | 37 | app.get('/send-external-request', async (_, res) => { 38 | await axios.get('https://example.com'); 39 | res.status(200).send("Done"); 40 | }); 41 | 42 | server = app.listen(0, () => { 43 | const port = server.address().port; 44 | console.error(`HTTP server listening on port ${port}`); 45 | if (process.send) { 46 | process.send(port); 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /test/instrumentations/express/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-express-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry express_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "body-parser": "^1.19.1", 13 | "express": "^4.9.8" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/instrumentations/fastify/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/fastify/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/fastify/app/fastify_app.js: -------------------------------------------------------------------------------- 1 | const lumigo = require('@lumigo/opentelemetry'); 2 | const fastify = require('fastify')({ 3 | logger: true, 4 | }); 5 | 6 | require('log-timestamp'); 7 | 8 | let tracerProvider; 9 | 10 | fastify.get('/test-scrubbing', async (request, reply) => { 11 | reply.send({ 12 | Authorization: 'SECRET', 13 | }); 14 | }); 15 | 16 | fastify.get('/', async (request, reply) => { 17 | reply.send('server is ready'); 18 | }); 19 | 20 | fastify.get('/basic', async (request, reply) => { 21 | await tracerProvider.forceFlush(); 22 | reply.header('Content-Type', 'text/plain').send('Hello world'); 23 | }); 24 | 25 | fastify.get('/quit', async (request, reply) => { 26 | console.error('Received quit command'); 27 | await tracerProvider.forceFlush(); 28 | reply.send({}).then(async () => { 29 | // fastify.close() takes too long to do its thing 30 | process.exit(0); 31 | }); 32 | }); 33 | 34 | fastify.listen({ port: 0 }, async (err, address) => { 35 | if (err) throw err; 36 | tracerProvider = (await lumigo.init).tracerProvider; 37 | const port = fastify.server.address().port; 38 | console.error(`HTTP server listening on port ${port}`); 39 | if (process.send) { 40 | process.send(port); 41 | } 42 | }); 43 | -------------------------------------------------------------------------------- /test/instrumentations/fastify/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-fastify-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry fastify_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "fastify": "^3.29.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/features/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/features/app/app.js: -------------------------------------------------------------------------------- 1 | const fastify = require('fastify')({ logger: true }); 2 | const bunyan = require('bunyan'); 3 | const bunyanLogger = bunyan.createLogger({ name: __filename }) 4 | const assert = require('assert'); 5 | 6 | let tracerProvider; 7 | let loggerProvider; 8 | 9 | fastify.get('/', async (request, reply) => { 10 | const lumigo = require('@lumigo/opentelemetry'); 11 | const lumigoSdk = await lumigo.init 12 | tracerProvider = lumigoSdk.tracerProvider; 13 | loggerProvider = lumigoSdk.loggerProvider; 14 | reply.send('init: all good') 15 | }); 16 | 17 | fastify.get('/sync-init', async (request, reply) => { 18 | const lumigo = require('@lumigo/opentelemetry/sync'); 19 | assert(typeof lumigo == "object", 'the default export from the sync entrypoint is not an object!'); 20 | assert(typeof lumigo.tracerProvider == "object", `lumigo.tracerProvider is not an object! (${typeof lumigo.tracerProvider})`); 21 | assert(typeof lumigo.loggerProvider == "object", `lumigo.default.loggerProvider is not an object! (${typeof lumigo.loggerProvider})`); 22 | 23 | bunyanLogger.info('this log should be exported to Lumigo without init'); 24 | reply.send('sync-init: all good') 25 | }); 26 | 27 | 28 | fastify.get('/quit', async (request, reply) => { 29 | bunyanLogger.info('this should not be exported to Lumigo'); 30 | 31 | console.log('Received quit command, flushing and exiting'); 32 | tracerProvider && await tracerProvider.forceFlush(); 33 | loggerProvider && await loggerProvider.forceFlush(); 34 | 35 | // we could have used fastify.close(), but it just takes too long 36 | reply.send({}).then(() => process.exit(0)) 37 | }); 38 | 39 | fastify.listen({ port: 0 }, async (err, address) => { 40 | if (err) { 41 | throw err; 42 | } 43 | const port = fastify.server.address().port; 44 | console.error(`HTTP server listening on port ${port}`); 45 | }); 46 | -------------------------------------------------------------------------------- /test/instrumentations/features/app/app.ts: -------------------------------------------------------------------------------- 1 | import { fastify as createFastify } from 'fastify'; 2 | import type { FastifyInstance } from 'fastify'; 3 | import * as bunyan from 'bunyan'; 4 | import lumigoSdk from '@lumigo/opentelemetry/sync'; 5 | 6 | const bunyanLogger = bunyan.createLogger({ name: __filename }) 7 | const assert = require('assert'); 8 | 9 | let tracerProvider; 10 | let loggerProvider; 11 | 12 | const fastify: FastifyInstance = createFastify({ logger: true }); 13 | 14 | fastify.get('/sync-init', async (request, reply) => { 15 | assert(typeof lumigoSdk == "object", 'the default export from the sync entrypoint is not an object!'); 16 | assert(typeof lumigoSdk.tracerProvider == "object", `lumigoSdk.tracerProvider is not an object! (${typeof lumigoSdk.tracerProvider})`); 17 | assert(typeof lumigoSdk.loggerProvider == "object", `lumigo.default.loggerProvider is not an object! (${typeof lumigoSdk.loggerProvider})`); 18 | bunyanLogger.info('this log should be exported to Lumigo without init'); 19 | reply.send('sync-init: all good') 20 | }); 21 | 22 | 23 | fastify.get('/quit', async (request, reply) => { 24 | bunyanLogger.info('this should not be exported to Lumigo'); 25 | 26 | console.log('Received quit command, flushing and exiting'); 27 | tracerProvider && await tracerProvider.forceFlush(); 28 | loggerProvider && await loggerProvider.forceFlush(); 29 | 30 | // we could have used fastify.close(), but it just takes too long 31 | reply.send({}).then(() => process.exit(0), (err) => { 32 | console.error('Failed to send response', err); 33 | process.exit(1) 34 | }); 35 | }); 36 | 37 | fastify.listen({ port: 0 }, async (err, address) => { 38 | if (err) { 39 | throw err; 40 | } 41 | const port = address.split(':').pop(); 42 | console.error(`HTTP server listening on port ${port}`); 43 | }); 44 | -------------------------------------------------------------------------------- /test/instrumentations/features/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-features-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry app.js", 7 | "start-sync": "node -r @lumigo/opentelemetry/sync app.js", 8 | "start-sync-ts": "ts-node -r @lumigo/opentelemetry/sync app.ts" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 14 | "fastify": "4.0.1", 15 | "bunyan": "1.8.15", 16 | "ts-node": "10.9.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/instrumentations/features/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "Node16", 4 | "module": "Node16", 5 | } 6 | } -------------------------------------------------------------------------------- /test/instrumentations/features/require-precedence/app-with-distro-dep/app.js: -------------------------------------------------------------------------------- 1 | const bunyan = require('bunyan'); 2 | const http = require('http'); 3 | 4 | const bunyanLogger = bunyan.createLogger({ name: __filename }) 5 | 6 | const server = http.createServer(async (req, res) => { 7 | switch (req.url) { 8 | case '/write-log': 9 | bunyanLogger.info('sure thing it works!'); 10 | res.writeHead(200); 11 | res.end(); 12 | break; 13 | case '/quit': 14 | res.writeHead(200); 15 | res.end('server is quitting'); 16 | server.close(); 17 | break; 18 | default: 19 | res.writeHead(404); 20 | res.end(`route handler for ${req.url} not found`); 21 | break; 22 | } 23 | }); 24 | 25 | server.listen(0, "localhost", () => console.error(`HTTP server listening on port ${server.address().port}`)); 26 | -------------------------------------------------------------------------------- /test/instrumentations/features/require-precedence/app-with-distro-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-features-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry/sync app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:./distro.tgz" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/instrumentations/features/require-precedence/app-with-logger-and-distro-deps/app.js: -------------------------------------------------------------------------------- 1 | const bunyan = require('bunyan'); 2 | const http = require('http'); 3 | 4 | const bunyanLogger = bunyan.createLogger({ name: __filename }) 5 | 6 | const server = http.createServer(async (req, res) => { 7 | switch (req.url) { 8 | case '/write-log': 9 | bunyanLogger.info('sure thing it works!'); 10 | res.writeHead(200); 11 | res.end(); 12 | break; 13 | case '/quit': 14 | res.writeHead(200); 15 | res.end('server is quitting'); 16 | server.close(); 17 | break; 18 | default: 19 | res.writeHead(404); 20 | res.end(`route handler for ${req.url} not found`); 21 | break; 22 | } 23 | }); 24 | 25 | server.listen(0, "localhost", () => console.error(`HTTP server listening on port ${server.address().port}`)); 26 | -------------------------------------------------------------------------------- /test/instrumentations/features/require-precedence/app-with-logger-and-distro-deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-features-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry/sync app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "bunyan": "1.8.15", 12 | "@lumigo/opentelemetry": "file:./distro.tgz" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/features/require-precedence/app-with-logger-dep/app.js: -------------------------------------------------------------------------------- 1 | const bunyan = require('bunyan'); 2 | const http = require('http'); 3 | 4 | const bunyanLogger = bunyan.createLogger({ name: __filename }) 5 | 6 | const server = http.createServer(async (req, res) => { 7 | switch (req.url) { 8 | case '/write-log': 9 | bunyanLogger.info('sure thing it works!'); 10 | res.writeHead(200); 11 | res.end(); 12 | break; 13 | case '/quit': 14 | res.writeHead(200); 15 | res.end('server is quitting'); 16 | server.close(); 17 | break; 18 | default: 19 | res.writeHead(404); 20 | res.end(`route handler for ${req.url} not found`); 21 | break; 22 | } 23 | }); 24 | 25 | server.listen(0, "localhost", () => console.error(`HTTP server listening on port ${server.address().port}`)); 26 | -------------------------------------------------------------------------------- /test/instrumentations/features/require-precedence/app-with-logger-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-features-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry/sync app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "bunyan": "1.8.15" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/instrumentations/features/require-precedence/distro-only/package.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "description": "This is a test package.json file for the case where the distro is loaded via NODE_PATH from another path", 4 | "dependencies": { 5 | "@lumigo/opentelemetry": "file:./distro.tgz" 6 | } 7 | } -------------------------------------------------------------------------------- /test/instrumentations/features/require-precedence/logger-only/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "bunyan": "1.8.15" 4 | } 5 | } -------------------------------------------------------------------------------- /test/instrumentations/grpc-js/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/grpc-js/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/grpc-js/app/greeter_server.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const PROTO_PATH = path.join(__dirname, './helloworld.proto'); 3 | 4 | const grpc = require('@grpc/grpc-js'); 5 | const protoLoader = require('@grpc/proto-loader'); 6 | const packageDefinition = protoLoader.loadSync(PROTO_PATH, { 7 | keepCase: true, 8 | longs: String, 9 | enums: String, 10 | defaults: true, 11 | oneofs: true, 12 | }); 13 | const hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld; 14 | 15 | function sayHelloUnaryUnary(call, callback) { 16 | callback(null, { message: `Hello ${call.request.name}` }); 17 | } 18 | 19 | function sayHelloUnaryStream(call) { 20 | for (let i = 0; i < 5; i++) { 21 | call.write({ message: `Hello ${call.request.name} ${i}` }); 22 | } 23 | call.end(); 24 | } 25 | 26 | function sayHelloStreamUnary(call, callback) { 27 | let names = []; 28 | call.on('data', function (request) { 29 | names.push(request.name); 30 | }); 31 | call.on('end', function () { 32 | callback(null, { message: `Hello ${names.join(', ')}` }); 33 | }); 34 | } 35 | 36 | function sayHelloStreamStream(call) { 37 | let counter = 0; 38 | call.on('data', function (request) { 39 | call.write({ message: `Hello ${request.name} ${++counter}` }); 40 | }); 41 | call.on('end', function () { 42 | call.end(); 43 | }); 44 | } 45 | 46 | class GreeterServer { 47 | isRunning = false; 48 | 49 | constructor(port) { 50 | let self = this; 51 | self.port = port; 52 | let server = new grpc.Server(); 53 | self.server = server; 54 | 55 | server.addService(hello_proto.Greeter.service, { 56 | sayHelloUnaryUnary, 57 | sayHelloUnaryStream, 58 | sayHelloStreamUnary, 59 | sayHelloStreamStream, 60 | }); 61 | 62 | server.bindAsync(`0.0.0.0:${port}`, grpc.ServerCredentials.createInsecure(), () => { 63 | server.start(); 64 | self.isRunning = true; 65 | console.error(`gRPC server listening on port ${port}`); 66 | }); 67 | } 68 | 69 | stop() { 70 | this.server.forceShutdown(); 71 | this.isRunning = false; 72 | } 73 | 74 | waitUntilReady() { 75 | return new Promise((resolve, reject) => { 76 | while (this.isRunning); 77 | resolve(); 78 | }); 79 | } 80 | } 81 | 82 | module.exports = { 83 | GreeterServer, 84 | }; 85 | -------------------------------------------------------------------------------- /test/instrumentations/grpc-js/app/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.helloworld"; 19 | option java_outer_classname = "HelloWorldProto"; 20 | option objc_class_prefix = "HLW"; 21 | 22 | package helloworld; 23 | 24 | // The greeting service definition. 25 | service Greeter { 26 | // Sends a greeting 27 | rpc SayHelloUnaryUnary (HelloRequest) returns (HelloReply) {} 28 | 29 | rpc SayHelloUnaryStream (HelloRequest) returns (stream HelloReply) {} 30 | 31 | rpc SayHelloStreamUnary (stream HelloRequest) returns (HelloReply) {} 32 | 33 | rpc SayHelloStreamStream (stream HelloRequest) returns (stream HelloReply) {} 34 | } 35 | 36 | // The request message containing the user's name. 37 | message HelloRequest { 38 | string name = 1; 39 | } 40 | 41 | // The response message containing the greetings 42 | message HelloReply { 43 | string message = 1; 44 | } 45 | -------------------------------------------------------------------------------- /test/instrumentations/grpc-js/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-grpc-roundtrip-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry grpc_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@grpc/grpc-js": "^1.8.2", 12 | "@lumigo/opentelemetry": "file:../../../../distro.tgz" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/http/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/http/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/http/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-http-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry http_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/instrumentations/ioredis/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/ioredis/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/ioredis/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-ioredis-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry ioredis_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "ioredis": "^4.0.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/kafkajs/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/kafkajs/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/kafkajs/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-kafkajs-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry kafkajs_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "kafkajs": "^2.2.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/kafkajs/kafkaJsTestUtils.js: -------------------------------------------------------------------------------- 1 | import { SpanKind, SpanStatusCode } from '@opentelemetry/api'; 2 | 3 | export function getExpectedResourceAttributes() { 4 | return { 5 | 'service.name': 'kafkajs', 6 | 'telemetry.sdk.language': 'nodejs', 7 | 'telemetry.sdk.name': 'opentelemetry', 8 | 'telemetry.sdk.version': expect.any(String), 9 | 'framework': expect.toBeOneOf(['node', 'express']), 10 | 'process.environ': expect.any(String), 11 | 'lumigo.distro.version': expect.stringMatching(/1\.\d+\.\d+/), 12 | 'process.pid': expect.any(Number), 13 | 'process.executable.name': 'node', 14 | 'process.runtime.description': 'Node.js', 15 | 'process.runtime.name': 'nodejs', 16 | 'process.runtime.version': expect.stringMatching(/\d+\.\d+\.\d+/), 17 | }; 18 | } 19 | 20 | export function getExpectedSpan({ spanKind, resourceAttributes, host, topic, message }) { 21 | let messageKey; 22 | switch (spanKind) { 23 | case SpanKind.PRODUCER: 24 | messageKey = 'messaging.produce.body'; 25 | break; 26 | case SpanKind.CONSUMER: 27 | messageKey = 'messaging.consume.body'; 28 | break; 29 | default: 30 | throw new Error('spanKind must be either SpanKind.PRODUCER or SpanKind.CONSUMER'); 31 | } 32 | return { 33 | traceId: expect.any(String), 34 | id: expect.any(String), 35 | timestamp: expect.any(Number), 36 | duration: expect.any(Number), 37 | name: topic, 38 | kind: spanKind, 39 | resource: { 40 | attributes: resourceAttributes, 41 | }, 42 | attributes: { 43 | 'messaging.destination': topic, 44 | 'messaging.destination_kind': 'topic', 45 | [messageKey]: JSON.stringify(message), 46 | 'messaging.system': 'kafka', 47 | }, 48 | status: { 49 | code: SpanStatusCode.UNSET, 50 | }, 51 | events: [], 52 | }; 53 | } 54 | 55 | export function filterKafkaJsSpans(spans, topic) { 56 | return spans.filter((span) => { 57 | return span.name == topic && span.attributes['messaging.destination'] == topic; 58 | }); 59 | } 60 | 61 | export function filterKafkaJsProduceSpans(spans) { 62 | return spans.filter((span) => span.kind == SpanKind.PRODUCER); 63 | } 64 | 65 | export function filterKakfkaConsumeSpans(spans) { 66 | return spans.filter((span) => span.kind == SpanKind.CONSUMER); 67 | } 68 | -------------------------------------------------------------------------------- /test/instrumentations/mongodb/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/mongodb/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/mongodb/app/dbUtils.js: -------------------------------------------------------------------------------- 1 | const {MongoClient} = require("mongodb"); 2 | 3 | const dbName = 'myProject'; 4 | 5 | class DB { 6 | static database; 7 | static client; 8 | 9 | static async setUp() { 10 | if(!this.client) { 11 | await this.setClient(); 12 | await this.setConnection(); 13 | } 14 | 15 | return this.database; 16 | } 17 | 18 | static async setConnection() { 19 | this.database = this.client.db(dbName); 20 | } 21 | 22 | static async setClient() { 23 | console.log("Connecting to database"); 24 | const client = new MongoClient(process.env.MONGODB_URL, { useUnifiedTopology: true }); 25 | await client.connect(); 26 | this.client = client; 27 | } 28 | 29 | static async closeConnection() { 30 | if (this.client) { 31 | this.client.close(); 32 | } 33 | } 34 | } 35 | 36 | module.exports = DB; -------------------------------------------------------------------------------- /test/instrumentations/mongodb/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-mongodb-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry mongodb_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "bson": "4.7.2", 13 | "mongodb": "^5.7.0" 14 | }, 15 | "devDependencies": { 16 | "async-await-retry": "^2.0.0", 17 | "denque": "^2.1.0", 18 | "optional-require": "^1.1.8" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/instrumentations/mongodb/mongodbTestUtils.js: -------------------------------------------------------------------------------- 1 | import { SpanKind, SpanStatusCode } from '@opentelemetry/api'; 2 | 3 | export function getExpectedResourceAttributes() { 4 | return { 5 | 'service.name': 'mongodb', 6 | 'telemetry.sdk.language': 'nodejs', 7 | 'telemetry.sdk.name': 'opentelemetry', 8 | 'telemetry.sdk.version': expect.any(String), 9 | 'framework': expect.toBeOneOf(['node', 'express']), 10 | 'process.environ': expect.any(String), 11 | 'lumigo.distro.version': expect.stringMatching(/1\.\d+\.\d+/), 12 | 'process.pid': expect.any(Number), 13 | 'process.executable.name': 'node', 14 | 'process.runtime.description': 'Node.js', 15 | 'process.runtime.name': 'nodejs', 16 | 'process.runtime.version': expect.stringMatching(/\d+\.\d+\.\d+/), 17 | }; 18 | } 19 | 20 | export function getExpectedSpan(nameSpanAttr, resourceAttributes, dbStatement) { 21 | return { 22 | traceId: expect.any(String), 23 | id: expect.any(String), 24 | timestamp: expect.any(Number), 25 | duration: expect.any(Number), 26 | name: nameSpanAttr, 27 | kind: SpanKind.CLIENT, 28 | resource: { 29 | attributes: resourceAttributes, 30 | }, 31 | attributes: { 32 | 'db.system': 'mongodb', 33 | 'db.name': 'myProject', 34 | 'db.mongodb.collection': 'insertOne', 35 | 'db.statement': dbStatement, 36 | }, 37 | status: { 38 | code: SpanStatusCode.UNSET, 39 | }, 40 | events: [], 41 | }; 42 | } 43 | 44 | export function getExpectedSpanWithParent( 45 | nameSpanAttr, 46 | resourceAttributes, 47 | dbStatement, 48 | dbCollection = 'insertOne' 49 | ) { 50 | return { 51 | traceId: expect.any(String), 52 | parentId: expect.any(String), 53 | id: expect.any(String), 54 | timestamp: expect.any(Number), 55 | duration: expect.any(Number), 56 | name: nameSpanAttr, 57 | kind: SpanKind.CLIENT, 58 | resource: { 59 | attributes: resourceAttributes, 60 | }, 61 | attributes: { 62 | 'db.system': 'mongodb', 63 | 'db.name': 'myProject', 64 | 'db.mongodb.collection': dbCollection, 65 | 'db.statement': dbStatement, 66 | }, 67 | status: { 68 | code: SpanStatusCode.UNSET, 69 | }, 70 | events: [], 71 | }; 72 | } 73 | 74 | export function filterMongoSpans(spans) { 75 | return spans.filter( 76 | (span) => span.name.includes('mongodb') && !span.name.includes('mongodb.isMaster') 77 | ); 78 | } 79 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | tsconfigRootDir: __dirname, 6 | sourceType: 'module', 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | /build 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | pnpm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | lerna-debug.log* 14 | 15 | # OS 16 | .DS_Store 17 | 18 | # Tests 19 | /coverage 20 | /.nyc_output 21 | 22 | # IDEs and editors 23 | /.idea 24 | .project 25 | .classpath 26 | .c9/ 27 | *.launch 28 | .settings/ 29 | *.sublime-workspace 30 | 31 | # IDE - VSCode 32 | .vscode/* 33 | !.vscode/settings.json 34 | !.vscode/tasks.json 35 | !.vscode/launch.json 36 | !.vscode/extensions.json 37 | 38 | # dotenv environment variable files 39 | .env 40 | .env.development.local 41 | .env.test.local 42 | .env.production.local 43 | .env.local 44 | 45 | # temp directory 46 | .temp 47 | .tmp 48 | 49 | # Runtime data 50 | pids 51 | *.pid 52 | *.seed 53 | *.pid.lock 54 | 55 | # Diagnostic reports (https://nodejs.org/api/report.html) 56 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 57 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src", 5 | "compilerOptions": { 6 | "deleteOutDir": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "private": true, 7 | "license": "UNLICENSED", 8 | "scripts": { 9 | "build": "nest build", 10 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 11 | "start": "nest start", 12 | "start:dev": "nest start --watch", 13 | "start:debug": "nest start --debug --watch", 14 | "start:prod": "node dist/main", 15 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 16 | "test": "jest", 17 | "test:watch": "jest --watch", 18 | "test:cov": "jest --coverage", 19 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 20 | "test:e2e": "jest --config ./test/jest-e2e.json" 21 | }, 22 | "dependencies": { 23 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 24 | "@nestjs/axios": "^3.0.2", 25 | "@nestjs/common": "^10.0.0", 26 | "@nestjs/core": "^10.3.2", 27 | "@nestjs/platform-express": "^10.0.0", 28 | "axios": "^1.6.7", 29 | "reflect-metadata": "^0.2.0", 30 | "rxjs": "^7.8.1" 31 | }, 32 | "devDependencies": { 33 | "@nestjs/cli": "^10.0.0", 34 | "@nestjs/schematics": "^10.0.0", 35 | "@nestjs/testing": "^10.0.0", 36 | "@types/express": "^4.17.17", 37 | "@types/jest": "^29.5.2", 38 | "@types/node": "^20.3.1", 39 | "@types/supertest": "^6.0.0", 40 | "@typescript-eslint/eslint-plugin": "^6.0.0", 41 | "@typescript-eslint/parser": "^6.0.0", 42 | "eslint": "^8.42.0", 43 | "eslint-config-prettier": "^9.0.0", 44 | "eslint-plugin-prettier": "^5.0.0", 45 | "jest": "^29.5.0", 46 | "prettier": "^3.0.0", 47 | "source-map-support": "^0.5.21", 48 | "supertest": "^6.3.3", 49 | "ts-jest": "^29.1.0", 50 | "ts-loader": "^9.4.3", 51 | "ts-node": "^10.9.1", 52 | "tsconfig-paths": "^4.2.0", 53 | "typescript": "^5.1.3" 54 | }, 55 | "jest": { 56 | "moduleFileExtensions": [ 57 | "js", 58 | "json", 59 | "ts" 60 | ], 61 | "rootDir": "src", 62 | "testRegex": ".*\\.spec\\.ts$", 63 | "transform": { 64 | "^.+\\.(t|j)s$": "ts-jest" 65 | }, 66 | "collectCoverageFrom": [ 67 | "**/*.(t|j)s" 68 | ], 69 | "coverageDirectory": "../coverage", 70 | "testEnvironment": "node" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AxiosResponse } from 'axios'; 3 | import { HttpService } from '@nestjs/axios'; 4 | 5 | @Controller() 6 | export class AppController { 7 | constructor(private readonly httpService: HttpService) {} 8 | 9 | @Get() 10 | async getHello(): Promise { 11 | const response: AxiosResponse = await this.httpService.get('https://jsonplaceholder.typicode.com/posts/1').toPromise(); 12 | return response.data; 13 | } 14 | 15 | @Get('quit') 16 | quit(): string { 17 | return 'ok'; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | import { HttpModule } from '@nestjs/axios'; 5 | 6 | @Module({ 7 | imports: [HttpModule], 8 | controllers: [AppController], 9 | providers: [AppService], 10 | }) 11 | export class AppModule {} 12 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/src/main.ts: -------------------------------------------------------------------------------- 1 | import * as lumigo from "@lumigo/opentelemetry"; 2 | import { NestFactory } from '@nestjs/core'; 3 | import { AppModule } from './app.module'; 4 | 5 | async function bootstrap() { 6 | await lumigo.init; 7 | const app = await NestFactory.create(AppModule); 8 | const port = parseInt(process.env.NEST_JS_PORT) | 3000; 9 | await app.listen(port); 10 | console.log(`listening on port ${port}`); 11 | } 12 | bootstrap(); 13 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /test/instrumentations/nestjs/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "ES2021", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": false, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/instrumentations/next/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/next/app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "node server.mjs", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 13 | "next": "^14.2.13", 14 | "react": "^18", 15 | "react-dom": "^18" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^20", 19 | "@types/react": "^18", 20 | "@types/react-dom": "^18", 21 | "postcss": "^8", 22 | "tailwindcss": "^3.4.1", 23 | "typescript": "^5" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/server.mjs: -------------------------------------------------------------------------------- 1 | import * as lumigo from "@lumigo/opentelemetry"; 2 | import { createServer } from "http"; 3 | import { parse } from "url"; 4 | import next from "next"; 5 | 6 | // Set up the environment and fallback port 7 | const port = process.env.PORT || 3000; // Default to port 3000 if PORT env is not set 8 | const dev = process.env.NODE_ENV !== "production"; 9 | await lumigo.init; 10 | const app = next({ dev }); 11 | const handle = app.getRequestHandler(); 12 | 13 | app.prepare().then(() => { 14 | createServer((req, res) => { 15 | const parsedUrl = parse(req.url, true); 16 | handle(req, res, parsedUrl); 17 | }).listen(port, (err) => { 18 | if (err) throw err; 19 | console.log(`listening on port ${port}`); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --background: #ffffff; 7 | --foreground: #171717; 8 | } 9 | 10 | @media (prefers-color-scheme: dark) { 11 | :root { 12 | --background: #0a0a0a; 13 | --foreground: #ededed; 14 | } 15 | } 16 | 17 | body { 18 | color: var(--foreground); 19 | background: var(--background); 20 | font-family: Arial, Helvetica, sans-serif; 21 | } 22 | 23 | @layer utilities { 24 | .text-balance { 25 | text-wrap: balance; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | 3 | export default function RootLayout({ 4 | children, 5 | }: Readonly<{ 6 | children: React.ReactNode; 7 | }>) { 8 | return ( 9 | 10 | 11 | {children} 12 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Hello World!

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/src/app/quit/page.tsx: -------------------------------------------------------------------------------- 1 | export default function Quit() { 2 | return ( 3 |
4 |

End.

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/src/pages/.keepme: -------------------------------------------------------------------------------- 1 | Having this empty folder should fix the following error: 2 | 3 | Couldn't find a `pages` directory. Please create one under the project root 4 | 5 | when running the test suite with Next 11.x -------------------------------------------------------------------------------- /test/instrumentations/next/app/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | const config: Config = { 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | colors: { 12 | background: "var(--background)", 13 | foreground: "var(--foreground)", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | }; 19 | export default config; 20 | -------------------------------------------------------------------------------- /test/instrumentations/next/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /test/instrumentations/pg/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/pg/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/pg/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-postgres-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry postgres_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "bson": "4.7.2", 13 | "pg": "^8.11.3" 14 | }, 15 | "devDependencies": { 16 | "async-await-retry": "^2.0.0", 17 | "denque": "^2.1.0", 18 | "optional-require": "^1.1.8" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/instrumentations/pg/app/postgres_app.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const { Client } = require('pg'); 3 | require('log-timestamp'); 4 | 5 | let config; 6 | let httpServer; 7 | 8 | async function sendPostgresDbRequest(res) { 9 | try { 10 | const client = new Client(config); 11 | await client.connect(); 12 | 13 | // Define the SQL query to create a table 14 | const createTableQuery = ` 15 | CREATE TABLE IF NOT EXISTS example_table ( 16 | id SERIAL PRIMARY KEY, 17 | name VARCHAR(100), 18 | age INT 19 | ) 20 | `; 21 | 22 | // Execute the query to create the table 23 | await client.query(createTableQuery); 24 | await client.end(); 25 | 26 | res.setHeader('Content-Type', 'application/json'); 27 | res.setHeader('access-control-allow-origin', '*'); 28 | res.writeHead(200); 29 | res.end(JSON.stringify('done')); 30 | } catch (e) { 31 | console.error(e); 32 | res.writeHead(404); 33 | res.end(JSON.stringify({ error: 'Resource not found' })); 34 | } 35 | } 36 | 37 | 38 | const requestListener = async (req, res) => { 39 | switch (req.url) { 40 | case '/': 41 | res.setHeader('Content-Type', 'application/json'); 42 | res.setHeader('access-control-allow-origin', '*'); 43 | res.writeHead(200); 44 | res.end(JSON.stringify('done')); 45 | break; 46 | 47 | case '/test-postgres': 48 | await sendPostgresDbRequest(res); 49 | break; 50 | 51 | case '/quit': 52 | console.error('Received quit command'); 53 | res.writeHead(200); 54 | res.end(JSON.stringify({})); 55 | httpServer.close(); 56 | process.exit(0); 57 | 58 | default: 59 | res.writeHead(404); 60 | res.end(JSON.stringify({ error: 'Resource not found' })); 61 | } 62 | }; 63 | 64 | 65 | (async () => { 66 | config = { 67 | host: process.env["POSTGRES_HOST"], 68 | port: parseInt(process.env["POSTGRES_PORT"]), 69 | database: process.env["POSTGRES_DATABASE"], 70 | user: process.env["POSTGRES_USER"], 71 | password: process.env["POSTGRES_PASSWORD"], 72 | }; 73 | httpServer = http.createServer(requestListener); 74 | httpServer.listen(0, 'localhost', () => { 75 | const port = httpServer.address().port; 76 | console.error(`HTTP server listening on port ${port}`); 77 | 78 | if (process.send) { 79 | process.send(port); 80 | } 81 | }); 82 | })(); 83 | -------------------------------------------------------------------------------- /test/instrumentations/pino/.gitignore: -------------------------------------------------------------------------------- 1 | logs -------------------------------------------------------------------------------- /test/instrumentations/pino/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/pino/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-pino-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry pino_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "pino": "^9.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/pino/app/pino_app.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const url = require('url'); 3 | const { init } = require("@lumigo/opentelemetry") 4 | 5 | require('log-timestamp'); 6 | 7 | const host = 'localhost'; 8 | let httpServer; 9 | 10 | function respond(res, status, body) { 11 | console.log(`responding with ${status} ${JSON.stringify(body)}`); 12 | res.setHeader('Content-Type', 'application/json'); 13 | res.setHeader('access-control-allow-origin', '*'); 14 | res.writeHead(status); 15 | res.end(JSON.stringify(body)); 16 | } 17 | 18 | const requestListener = async function (req, res) { 19 | await init; 20 | 21 | const pinoLogger = require('pino')() 22 | 23 | console.error(`Received request: ${req.method} ${req.url}`); 24 | 25 | const requestUrl = url.parse(req.url, true); 26 | 27 | switch (requestUrl.pathname) { 28 | case '/write-log-line': 29 | try { 30 | const logLine = JSON.parse(requestUrl?.query?.logLine) 31 | pinoLogger.info(logLine); 32 | respond(res, 200, {}) 33 | } catch (err) { 34 | console.error(`Error writing log line`, err); 35 | respond(res, 500, { error: err }); 36 | } 37 | break; 38 | 39 | case '/quit': 40 | console.error('Received quit command'); 41 | respond(res, 200, {}); 42 | httpServer.close(); 43 | break; 44 | 45 | default: 46 | respond(res, 404, { error: 'Resource not found' }); 47 | } 48 | }; 49 | 50 | httpServer = http.createServer(requestListener); 51 | httpServer.listen(0, host, () => { 52 | const port = httpServer.address().port; 53 | console.error(`HTTP server listening on port ${port}`); 54 | if (process.send) { 55 | process.send(port); 56 | } 57 | }); 58 | -------------------------------------------------------------------------------- /test/instrumentations/prisma/.gitignore: -------------------------------------------------------------------------------- 1 | spans 2 | -------------------------------------------------------------------------------- /test/instrumentations/prisma/mysql_app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | prisma/migrations 3 | prisma_app.js 4 | -------------------------------------------------------------------------------- /test/instrumentations/prisma/mysql_app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-prisma-mysql-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "clean": "rm -f prisma_app.js && rm -rf prisma/migrations", 7 | "copy": "cp ../app_shared_resources/prisma_app.js .", 8 | "prep_db": "npm run clean && prisma generate && prisma db push", 9 | "setup": "npm run prep_db && npm run copy", 10 | "start": "node -r @lumigo/opentelemetry prisma_app.js", 11 | "teardown": "npm run clean" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 17 | "@prisma/client": "^4.2.0", 18 | "prisma": "^4.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/instrumentations/prisma/mysql_app/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator client { 7 | provider = "prisma-client-js" 8 | previewFeatures = ["tracing"] 9 | } 10 | 11 | model User { 12 | id Int @id @default(autoincrement()) 13 | createdAt DateTime @default(now()) 14 | email String @unique 15 | name String? 16 | role Role @default(USER) 17 | posts Post[] 18 | } 19 | 20 | model Post { 21 | id Int @id @default(autoincrement()) 22 | createdAt DateTime @default(now()) 23 | updatedAt DateTime @updatedAt 24 | published Boolean @default(false) 25 | title String @db.VarChar(255) 26 | author User? @relation(fields: [authorId], references: [id]) 27 | authorId Int? 28 | } 29 | 30 | enum Role { 31 | USER 32 | ADMIN 33 | } 34 | -------------------------------------------------------------------------------- /test/instrumentations/prisma/postgres_app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | prisma/migrations 3 | prisma_app.js 4 | -------------------------------------------------------------------------------- /test/instrumentations/prisma/postgres_app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-prisma-postgres-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "clean": "rm -f prisma_app.js && rm -rf prisma/migrations", 7 | "copy": "cp ../app_shared_resources/prisma_app.js .", 8 | "prep_db": "npm run clean && prisma generate && prisma db push", 9 | "setup": "npm run prep_db && npm run copy", 10 | "start": "node -r @lumigo/opentelemetry prisma_app.js", 11 | "teardown": "npm run clean" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 17 | "@prisma/client": "^4.2.0", 18 | "prisma": "^4.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/instrumentations/prisma/postgres_app/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator client { 7 | provider = "prisma-client-js" 8 | previewFeatures = ["tracing"] 9 | } 10 | 11 | model User { 12 | id Int @id @default(autoincrement()) 13 | createdAt DateTime @default(now()) 14 | email String @unique 15 | name String? 16 | role Role @default(USER) 17 | posts Post[] 18 | } 19 | 20 | model Post { 21 | id Int @id @default(autoincrement()) 22 | createdAt DateTime @default(now()) 23 | updatedAt DateTime @updatedAt 24 | published Boolean @default(false) 25 | title String @db.VarChar(255) 26 | author User? @relation(fields: [authorId], references: [id]) 27 | authorId Int? 28 | } 29 | 30 | enum Role { 31 | USER 32 | ADMIN 33 | } 34 | -------------------------------------------------------------------------------- /test/instrumentations/redis/.gitignore: -------------------------------------------------------------------------------- 1 | spans -------------------------------------------------------------------------------- /test/instrumentations/redis/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/redis/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-redis-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry redis_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "@lumigo/opentelemetry": "file:../../../../distro.tgz", 12 | "redis": "^4.0.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/instrumentations/redis/redisTestUtils.ts: -------------------------------------------------------------------------------- 1 | import { SpanKind, SpanStatusCode } from '@opentelemetry/api'; 2 | 3 | export function getExpectedResourceAttributes() { 4 | return { 5 | 'service.name': 'redis', 6 | 'telemetry.sdk.language': 'nodejs', 7 | 'telemetry.sdk.name': 'opentelemetry', 8 | 'telemetry.sdk.version': expect.any(String), 9 | 'framework': expect.toBeOneOf(['node', 'express']), 10 | 'process.environ': expect.any(String), 11 | 'lumigo.distro.version': expect.stringMatching(/1\.\d+\.\d+/), 12 | 'process.pid': expect.any(Number), 13 | 'process.executable.name': 'node', 14 | 'process.runtime.description': 'Node.js', 15 | 'process.runtime.name': 'nodejs', 16 | 'process.runtime.version': expect.stringMatching(/\d+\.\d+\.\d+/), 17 | }; 18 | } 19 | 20 | export function getExpectedSpan({ 21 | nameSpanAttr, 22 | resourceAttributes, 23 | host, 24 | dbStatement = undefined, 25 | responseBody = undefined, 26 | }: { 27 | nameSpanAttr: string, 28 | resourceAttributes: any, 29 | host: string, 30 | dbStatement?: string, 31 | responseBody?: unknown, 32 | }) { 33 | const expectedSpan = { 34 | traceId: expect.any(String), 35 | id: expect.any(String), 36 | timestamp: expect.any(Number), 37 | duration: expect.any(Number), 38 | name: nameSpanAttr, 39 | kind: SpanKind.CLIENT, 40 | resource: { 41 | attributes: resourceAttributes, 42 | }, 43 | attributes: { 44 | 'db.system': 'redis', 45 | 'net.peer.name': host, 46 | 'net.peer.port': expect.any(Number), 47 | }, 48 | status: { 49 | code: SpanStatusCode.UNSET, 50 | }, 51 | events: [], 52 | }; 53 | if (dbStatement) { 54 | expectedSpan.attributes['db.statement'] = JSON.stringify(dbStatement); 55 | } 56 | if (responseBody) { 57 | expectedSpan.attributes['db.response.body'] = JSON.stringify(responseBody); 58 | } 59 | 60 | return expectedSpan; 61 | } 62 | 63 | export function filterRedisSpans(spans) { 64 | return spans.filter((span) => span.name.indexOf('redis-') == 0); 65 | } 66 | -------------------------------------------------------------------------------- /test/instrumentations/winston/.gitignore: -------------------------------------------------------------------------------- 1 | logs -------------------------------------------------------------------------------- /test/instrumentations/winston/app/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json -------------------------------------------------------------------------------- /test/instrumentations/winston/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-winston-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "node -r @lumigo/opentelemetry/sync winston_app.js" 7 | }, 8 | "author": "", 9 | "license": "ISC" 10 | } 11 | -------------------------------------------------------------------------------- /test/instrumentations/winston/app/winston_app.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const url = require('url'); 3 | const winston = require('winston'); 4 | 5 | const winstonLogger = winston.createLogger({ 6 | transports: [new winston.transports.Console()], 7 | }) 8 | 9 | const host = 'localhost'; 10 | let httpServer; 11 | 12 | function respond(res, status, body) { 13 | console.log(`responding with ${status} ${JSON.stringify(body)}`); 14 | res.setHeader('Content-Type', 'application/json'); 15 | res.setHeader('access-control-allow-origin', '*'); 16 | res.writeHead(status); 17 | res.end(JSON.stringify(body)); 18 | } 19 | 20 | const requestListener = async function (req, res) { 21 | console.log(`Received request: ${req.method} ${req.url}`); 22 | const requestUrl = url.parse(req.url, true); 23 | 24 | switch (requestUrl.pathname) { 25 | case '/write-log-line': 26 | try { 27 | const logLine = JSON.parse(requestUrl?.query?.logLine) 28 | winstonLogger.info(logLine); 29 | respond(res, 200, {}) 30 | } catch (err) { 31 | console.error(`Error writing log line`, err); 32 | respond(res, 500, { error: err }); 33 | } 34 | break; 35 | 36 | case '/quit': 37 | console.error('Received quit command'); 38 | respond(res, 200, {}); 39 | httpServer.close(); 40 | break; 41 | 42 | default: 43 | respond(res, 404, { error: 'Resource not found' }); 44 | } 45 | }; 46 | 47 | httpServer = http.createServer(requestListener); 48 | httpServer.listen(0, host, () => { 49 | const port = httpServer.address().port; 50 | console.error(`HTTP server listening on port ${port} `); 51 | if (process.send) { 52 | process.send(port); 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /test/instrumentations/winston/deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@lumigo/opentelemetry": "file:./distro.tgz" 4 | } 5 | } -------------------------------------------------------------------------------- /test/integration/setup.ts: -------------------------------------------------------------------------------- 1 | import jestGlobals from '@jest/globals'; 2 | import { instrumentationsVersionManager } from '../helpers/InstrumentationsVersionManager'; 3 | 4 | /** 5 | * @param testName: string 6 | * @param packageName: string 7 | * @param version: string 8 | * @param timeout: number 9 | * @param testCode: Callable, function to test 10 | */ 11 | export const itTest = function ( 12 | { 13 | testName, 14 | packageName, 15 | version, 16 | timeout, 17 | }: { 18 | testName: string, 19 | packageName: string, 20 | version: string, 21 | timeout?: number, 22 | }, 23 | testCode: () => Promise 24 | ) { 25 | global.console = require('console'); 26 | jestGlobals.test( 27 | testName, 28 | async function () { 29 | try { 30 | console.info(`Starting the test: ${testName}\n`); 31 | 32 | await testCode(); 33 | instrumentationsVersionManager.addPackageSupportedVersion(packageName, version); 34 | console.info(`Test ${testName} was finished successfully`); 35 | console.info( 36 | `Current state of instrumentationsVersionManager: ${JSON.stringify( 37 | instrumentationsVersionManager.getInstrumentationsVersions() 38 | )}` 39 | ); 40 | } catch (e) { 41 | console.error(`Test ${testName} failed!`, e); 42 | instrumentationsVersionManager.addPackageUnsupportedVersion(packageName, version); 43 | console.info( 44 | `Current state of instrumentationsVersionManager: ${JSON.stringify( 45 | instrumentationsVersionManager.getInstrumentationsVersions() 46 | )}` 47 | ); 48 | throw e; 49 | } 50 | }, 51 | timeout 52 | ); 53 | }; 54 | -------------------------------------------------------------------------------- /test/utils/aws-sdk-helpers.ts: -------------------------------------------------------------------------------- 1 | import {Span} from '@opentelemetry/sdk-trace-base'; 2 | import type { SQS as SQSClient } from 'aws-sdk'; 3 | 4 | export const testAppQueryParams = ({ region, queueUrl, sqsPort }: { region: string, queueUrl: string, sqsPort: number }) => 5 | Object.entries({ 6 | region, 7 | sqsPort, 8 | queueUrl: encodeURIComponent(queueUrl) 9 | }).map(keyValue => keyValue.join('=')).join('&') 10 | 11 | export const createTempQueue = async ({ sqsClient, sqsPort }: { sqsClient: SQSClient, sqsPort: number }) => { 12 | const queueName = `test-queue-${Math.random().toString(36).substring(7)}`; 13 | await sqsClient.createQueue({ QueueName: queueName }).promise() 14 | const queueUrl = `http://localhost:${sqsPort}/000000000000/${queueName}` 15 | 16 | return { queueUrl, queueName } 17 | } 18 | 19 | export const filterAwsSdkInstrumentationSpans = (spans: Span[]) => 20 | spans.filter(span => { 21 | if (span.attributes['http.request.headers']) { 22 | const headers = JSON.parse(span.attributes['http.request.headers'] as string) 23 | return headers['user-agent']?.includes('aws-sdk') 24 | } 25 | 26 | return false 27 | }) 28 | -------------------------------------------------------------------------------- /test/utils/common.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from "fs"; 2 | 3 | export function readDumpFile(dumpFilePath: string): T[] { 4 | try { 5 | return readFileSync(dumpFilePath, 'utf-8').split(/\r?\n/).filter(Boolean).map(line => JSON.parse(line)); 6 | } catch (err) { 7 | // Might be that we try to read as a new record is being written, and the JSON is still malformed 8 | return []; 9 | } 10 | } -------------------------------------------------------------------------------- /test/utils/spans.ts: -------------------------------------------------------------------------------- 1 | import { SpanKind } from '@opentelemetry/api'; 2 | import { BasicTracerProvider, Span } from '@opentelemetry/sdk-trace-base'; 3 | 4 | export { Span } from '@opentelemetry/sdk-trace-base'; 5 | export { LogRecord } from '@opentelemetry/sdk-logs'; 6 | 7 | export function getSpanByName(spans: Span[] = [], spanName: string) { 8 | return spans.find((span) => span.name === spanName); 9 | } 10 | 11 | export function getSpanByKind(spans: Span[] = [], spanKindValue: SpanKind): Span { 12 | return spans.find((span) => span.kind === spanKindValue) as Span; 13 | } 14 | 15 | export function getSpansByKind(spans: Span[] = [], spanKindValue: SpanKind): Span[] { 16 | return spans.filter((span) => span.kind === spanKindValue); 17 | } 18 | 19 | export const getSpansByAttribute = (spans: Span[], attributeKey: string, attributeValue: unknown): Span[] => { 20 | return spans.filter((span) => span.attributes[attributeKey] === attributeValue); 21 | } 22 | 23 | export const rootSpanWithAttributes = (attributes: Record, kind?: SpanKind): Span => { 24 | const provider = new BasicTracerProvider(); 25 | const root = provider.getTracer('default').startSpan('root', { kind, attributes }); 26 | root.setAttributes(attributes); 27 | 28 | return root as Span; 29 | }; -------------------------------------------------------------------------------- /test/utils/time.ts: -------------------------------------------------------------------------------- 1 | export const sleep = async(millis: number) => new Promise(resolve => setTimeout(resolve, millis)); -------------------------------------------------------------------------------- /test/utils/versions.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs'; 2 | import { dirname } from 'path'; 3 | import { instrumentationsVersionManager } from '../helpers/InstrumentationsVersionManager'; 4 | 5 | const VERSION_UNDER_TEST = 6 | process.env.INSTRUMENTATION_UNDER_TEST && 7 | process.env.INSTRUMENTATION_UNDER_TEST.length > 0 && 8 | process.env.VERSION_UNDER_TEST && 9 | process.env.VERSION_UNDER_TEST.length > 0 10 | ? process.env.VERSION_UNDER_TEST 11 | : undefined; 12 | 13 | export function versionsToTest(instrumentationName: string, packageName: string) { 14 | const runtimeVersion = parseInt(process.version.slice(1).split('.')[0]); 15 | if (VERSION_UNDER_TEST) { 16 | return [VERSION_UNDER_TEST]; 17 | } 18 | const allVersions = readFileSync( 19 | `${dirname( 20 | dirname(__dirname) 21 | )}/src/instrumentations/${instrumentationName}/tested_versions/${runtimeVersion}/${packageName}` 22 | ) 23 | .toString() 24 | .split('\n') 25 | .filter(Boolean); 26 | const supportedVersions = allVersions.filter((version) => !version.startsWith('!')); 27 | const unsupportedVersions = allVersions 28 | .filter((version) => version.startsWith('!')) 29 | .map((version) => { 30 | // strip ! prefix from version 31 | return version.slice(1); 32 | }); 33 | unsupportedVersions.forEach((version) => { 34 | instrumentationsVersionManager.addPackageUnsupportedVersion(packageName, version); 35 | }); 36 | return supportedVersions; 37 | } 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "allowJs": true, 5 | "target": "es6", 6 | "module": "CommonJS", 7 | "moduleResolution": "node", 8 | "sourceMap": true, 9 | "inlineSources": true, 10 | "allowSyntheticDefaultImports": true, 11 | "esModuleInterop": true, 12 | "resolveJsonModule": true, 13 | "rootDir": ".", 14 | "experimentalDecorators": true, 15 | "noImplicitOverride": true, 16 | "declaration": true, 17 | "declarationMap": true, 18 | "composite": true, 19 | "importsNotUsedAsValues": "error" 20 | }, 21 | "include": ["./src/**/*", "./src/**/*.json", "./package.json"], 22 | "exclude": ["**/*.test.js", "**/*.test.ts"] 23 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const nodeExternals = require('webpack-node-externals'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | entry: './src/expressAppProgrammatically.ts', 6 | mode: 'production', 7 | devtool: 'source-map', 8 | target: 'node', 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.(ts|js)x?$/, 13 | use: 'ts-loader', 14 | }, 15 | ], 16 | }, 17 | optimization: { 18 | minimize: false 19 | }, 20 | externals: [ 21 | nodeExternals({ 22 | allowlist: [ 23 | 'axios' 24 | ], 25 | }), 26 | ], 27 | resolve: { 28 | // fallback: { 29 | // "crypto": require.resolve("crypto-browserify"), 30 | // util: require.resolve("util/") 31 | // }, 32 | extensions: ['.tsx', '.ts', '.js'], 33 | }, 34 | 35 | output: { 36 | globalObject: 'this', 37 | library: '@lumigo/opentelemetry', 38 | filename: 'distro.js', 39 | libraryTarget: 'umd', 40 | umdNamedDefine: true, 41 | path: path.resolve(__dirname, 'dist'), 42 | }, 43 | }; 44 | -------------------------------------------------------------------------------- /webpack.config2.js: -------------------------------------------------------------------------------- 1 | const nodeExternals = require('webpack-node-externals'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | entry: './src/distro.ts', 6 | mode: 'production', 7 | devtool: 'source-map', 8 | target: 'node', 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.(ts|js)x?$/, 13 | use: 'ts-loader', 14 | }, 15 | ], 16 | }, 17 | optimization: { 18 | minimize: false 19 | }, 20 | externals: [ 21 | nodeExternals({ 22 | allowlist: [ 23 | '@opentelemetry/api', 24 | '@opentelemetry/auto-instrumentations-node', 25 | '@opentelemetry/core', 26 | '@opentelemetry/exporter-jaeger', 27 | '@opentelemetry/exporter-trace-otlp-http', 28 | '@opentelemetry/instrumentation', 29 | '@opentelemetry/instrumentation-http', 30 | '@opentelemetry/resources', 31 | '@opentelemetry/sdk-node', 32 | '@opentelemetry/sdk-trace-base', 33 | '@opentelemetry/sdk-trace-node', 34 | '@opentelemetry/semantic-conventions', 35 | ], 36 | }), 37 | ], 38 | resolve: { 39 | // fallback: { 40 | // "crypto": require.resolve("crypto-browserify"), 41 | // util: require.resolve("util/") 42 | // }, 43 | extensions: ['.tsx', '.ts', '.js'], 44 | }, 45 | 46 | output: { 47 | globalObject: 'this', 48 | library: '@lumigo/opentelemetry', 49 | filename: 'distro.js', 50 | libraryTarget: 'umd', 51 | umdNamedDefine: true, 52 | path: path.resolve(__dirname, 'dist'), 53 | }, 54 | }; 55 | --------------------------------------------------------------------------------