From 3a2c28835eace21d42bc8cc90d2fcb3e730da801 Mon Sep 17 00:00:00 2001 From: NathanSavageKaimai <135352038+NathanSavageKaimai@users.noreply.github.com> Date: Tue, 1 Sep 2026 14:23:28 +0100 Subject: [PATCH 1/2] feat: instrumentation based opentelemetry collection (#3361) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `@crawlee/otel`, an OpenTelemetry instrumentation for Crawlee v4. It patches the crawler classes as they are imported, so an existing crawler produces traces and logs without any change to its own code. Closes #2955 ## What it does **Automatic instrumentation.** `CrawleeInstrumentation` plugs into the OpenTelemetry SDK like any other instrumentation and patches these methods: | Module | Method | Span name | Kind | | --- | --- | --- | --- | | `@crawlee/basic` | `BasicCrawler.run` | `crawlee.crawler.run` | internal | | `@crawlee/basic` | `BasicCrawler.handleRequest` | `crawlee.crawler.handleRequest` | internal | | `@crawlee/basic` | `BasicCrawler.runRequestHandler` | `crawlee.crawler.runRequestHandler` | internal | | `@crawlee/basic` | `BasicCrawler.requestFunctionErrorHandler` | `crawlee.crawler.requestFunctionErrorHandler` | internal | | `@crawlee/basic` | `BasicCrawler.handleFailedRequestHandler` | `crawlee.crawler.handleFailedRequestHandler` | internal | | `@crawlee/http` | `HttpCrawler.makeHttpRequest` | `crawlee.http.makeHttpRequest` | client | | `@crawlee/browser` | `BrowserCrawler.navigate` | `crawlee.browser.navigate` | client | Every span carries `code.function.name`, the `run` span carries `crawlee.crawler.type`, and the methods that receive a crawling context also carry `url.full`, `http.request.method`, `crawlee.request.id`, and `crawlee.request.retry_count`. `url.full` and `http.request.method` are the stable semantic conventions, so the traces stay comparable with other instrumented HTTP clients; Crawlee data with no convention keeps the `crawlee.` prefix. A method that is missing from the installed Crawlee version is skipped with a warning instead of breaking the module load. **Log forwarding.** Patches the logging methods Crawlee derives in `BaseCrawleeLogger`, so `log.info()`, `log.exception()`, and the rest are emitted as OpenTelemetry log records with the Crawlee level mapped onto the OpenTelemetry severity. Because every v4 logger derives from that base, a Winston, Pino, or hand-written adapter is forwarded just like the default one. The structured `data` of a log call becomes the record attributes, and an `Error` in it becomes `exception.type`, `exception.message`, and `exception.stacktrace`. **Manual spans.** `wrapWithSpan()` wraps a request handler, a hook, or any other function. The span name and options are either static or computed from the call arguments. A synchronous function stays synchronous. **Custom instrumentation.** `customInstrumentation` takes module, class, and method triples, so a class the package does not know about can be patched the same way. `requestHandlingInstrumentation` and `logInstrumentation` switch the two built-in groups off. Errors set `SpanStatusCode.ERROR` and record an exception event. Success is left `UNSET`, following the OpenTelemetry guidance that an instrumentation should not claim a span succeeded. ## Setup Automatic instrumentation needs the OpenTelemetry module hook installed before anything imports Crawlee, and ESM imports are hoisted, so the hook and the SDK setup have to sit in preloaded files rather than at the top of the crawler: ```js // otel-hook.js import { register } from 'node:module'; import { pathToFileURL } from 'node:url'; register('@opentelemetry/instrumentation/hook.mjs', pathToFileURL('./')); ``` ```bash node --import ./otel-hook.js --import ./otel-setup.js ./main.js ``` `otel-setup.js` builds the `NodeSDK` with `CrawleeInstrumentation` and owns the shutdown flush. The guide has both files in full. The example in this repo runs with: ```bash pnpm exec tsx \ --import ./docs/guides/trace_and_monitor_register_hook.ts \ --import ./docs/guides/trace_and_monitor_setup.ts \ ./docs/guides/trace_and_monitor_basic.ts ``` Verified end to end against Jaeger over OTLP/gRPC. One thing worth knowing: Jaeger is a tracing backend and rejects OTLP logs, so the forwarded logs need a collector or a backend that ingests them. The guide calls that out. ## Docs New guide at `docs/guides/trace-and-monitor-crawlers.mdx`, with runnable snippets for the setup, `wrapWithSpan`, and custom instrumentation, the configuration reference, and the full list of automatically instrumented methods and attributes. ## Dependencies `@opentelemetry/instrumentation` and `@opentelemetry/semantic-conventions` are dependencies. `@opentelemetry/api` and `@opentelemetry/api-logs` are peer dependencies, so the package shares the host application's API instance. --------- Co-authored-by: Josef Procházka Co-authored-by: Josef Prochazka Co-authored-by: Claude Opus 5 --- docs/guides/trace-and-monitor-crawlers.mdx | 279 ++++++ docs/guides/trace_and_monitor_basic.ts | 19 + docs/guides/trace_and_monitor_custom.ts | 78 ++ .../guides/trace_and_monitor_register_hook.ts | 6 + docs/guides/trace_and_monitor_setup.ts | 59 ++ .../trace_and_monitor_wrap_with_span.ts | 87 ++ docs/package.json | 7 + docs/public-api/crawlee-otel.api.md | 50 ++ package.json | 9 + .../src/internals/basic-crawler.ts | 7 +- packages/otel/.npmignore | 5 + packages/otel/CHANGELOG.md | 4 + packages/otel/README.md | 81 ++ packages/otel/package.json | 56 ++ packages/otel/src/constants.ts | 214 +++++ packages/otel/src/index.ts | 3 + packages/otel/src/instrumentation.ts | 227 +++++ packages/otel/src/internal-types.ts | 41 + packages/otel/src/types.ts | 27 + packages/otel/src/utilities.ts | 113 +++ packages/otel/src/wrapWithSpan.ts | 148 +++ packages/otel/test/constants.test.ts | 33 + packages/otel/test/instrumentation.test.ts | 323 +++++++ packages/otel/test/patching.test.ts | 416 +++++++++ packages/otel/test/tsconfig.json | 7 + packages/otel/test/utilities.test.ts | 221 +++++ packages/otel/test/wrap-with-span.test.ts | 444 +++++++++ packages/otel/tsconfig.build.json | 8 + packages/otel/tsconfig.json | 4 + pnpm-lock.yaml | 844 +++++++++++++++++- test/otel/fixtures/crawler.ts | 14 + test/otel/fixtures/otel-setup.ts | 23 + test/otel/fixtures/register-hook.ts | 6 + test/otel/hook-delivery.test.ts | 68 ++ test/otel/instrumentation.test.ts | 192 ++++ test/otel/log-forwarding.test.ts | 93 ++ test/otel/patched-methods.test.ts | 52 ++ test/otel/tracer-wiring.test.ts | 66 ++ website/docusaurus.config.js | 2 + website/sidebars.js | 1 + website/static/img/jaeger-search.png | Bin 0 -> 395443 bytes 41 files changed, 4326 insertions(+), 11 deletions(-) create mode 100644 docs/guides/trace-and-monitor-crawlers.mdx create mode 100644 docs/guides/trace_and_monitor_basic.ts create mode 100644 docs/guides/trace_and_monitor_custom.ts create mode 100644 docs/guides/trace_and_monitor_register_hook.ts create mode 100644 docs/guides/trace_and_monitor_setup.ts create mode 100644 docs/guides/trace_and_monitor_wrap_with_span.ts create mode 100644 docs/public-api/crawlee-otel.api.md create mode 100644 packages/otel/.npmignore create mode 100644 packages/otel/CHANGELOG.md create mode 100644 packages/otel/README.md create mode 100644 packages/otel/package.json create mode 100644 packages/otel/src/constants.ts create mode 100644 packages/otel/src/index.ts create mode 100644 packages/otel/src/instrumentation.ts create mode 100644 packages/otel/src/internal-types.ts create mode 100644 packages/otel/src/types.ts create mode 100644 packages/otel/src/utilities.ts create mode 100644 packages/otel/src/wrapWithSpan.ts create mode 100644 packages/otel/test/constants.test.ts create mode 100644 packages/otel/test/instrumentation.test.ts create mode 100644 packages/otel/test/patching.test.ts create mode 100644 packages/otel/test/tsconfig.json create mode 100644 packages/otel/test/utilities.test.ts create mode 100644 packages/otel/test/wrap-with-span.test.ts create mode 100644 packages/otel/tsconfig.build.json create mode 100644 packages/otel/tsconfig.json create mode 100644 test/otel/fixtures/crawler.ts create mode 100644 test/otel/fixtures/otel-setup.ts create mode 100644 test/otel/fixtures/register-hook.ts create mode 100644 test/otel/hook-delivery.test.ts create mode 100644 test/otel/instrumentation.test.ts create mode 100644 test/otel/log-forwarding.test.ts create mode 100644 test/otel/patched-methods.test.ts create mode 100644 test/otel/tracer-wiring.test.ts create mode 100644 website/static/img/jaeger-search.png diff --git a/docs/guides/trace-and-monitor-crawlers.mdx b/docs/guides/trace-and-monitor-crawlers.mdx new file mode 100644 index 000000000000..23ae6db87f08 --- /dev/null +++ b/docs/guides/trace-and-monitor-crawlers.mdx @@ -0,0 +1,279 @@ +--- +id: trace-and-monitor-crawlers +title: Trace and monitor crawlers +description: How to use OpenTelemetry to trace and monitor your crawlers +--- + +import CodeBlock from '@theme/CodeBlock'; + +import RegisterHookSource from '!!raw-loader!./trace_and_monitor_register_hook.ts'; +import SetupSource from '!!raw-loader!./trace_and_monitor_setup.ts'; +import BasicExampleSource from '!!raw-loader!./trace_and_monitor_basic.ts'; +import WrapWithSpanSource from '!!raw-loader!./trace_and_monitor_wrap_with_span.ts'; +import CustomInstrumentationSource from '!!raw-loader!./trace_and_monitor_custom.ts'; + +[OpenTelemetry](https://opentelemetry.io/) is a collection of APIs, SDKs, and tools to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) to help you analyze your software's performance and behavior. You can learn more about its basic concepts in the [OpenTelemetry documentation](https://opentelemetry.io/docs/concepts/). + +In this guide, we'll show you how to set up OpenTelemetry and instrument your Crawlee crawlers to see traces of individual requests as they are processed. OpenTelemetry on its own does not provide visualization tools, so we'll use [Jaeger](https://www.jaegertracing.io/) as our tracing backend. Feel free to use any other OpenTelemetry-compatible backend. Check the [OpenTelemetry vendors list](https://opentelemetry.io/ecosystem/vendors/) for more options. + +## Set up Jaeger + +This guide will show you how to set up the environment locally to run the example code and visualize the telemetry data in Jaeger running in a [Docker](https://docs.docker.com/engine/install/) container. +To start the preconfigured Docker container, create a `docker-compose.yml` file: + +```yaml +services: + jaeger: + image: jaegertracing/all-in-one:1.53 + container_name: jaeger + ports: + # Jaeger UI + - "16686:16686" + # OTLP gRPC + - "4317:4317" + # OTLP HTTP + - "4318:4318" + environment: + - COLLECTOR_OTLP_ENABLED=true + restart: unless-stopped +``` + +Then start it with: + +```bash +docker compose up -d +``` + +For more details about the Jaeger setup, see the [getting started section](https://www.jaegertracing.io/docs/latest/getting-started/) in their documentation. You can see the Jaeger UI in your browser by navigating to [http://localhost:16686](http://localhost:16686). + +## Install dependencies + +To instrument your Crawlee crawler, you need to install the `@crawlee/otel` package along with the OpenTelemetry SDK packages: + +```bash npm2yarn +npm install @crawlee/otel @opentelemetry/api @opentelemetry/api-logs @opentelemetry/sdk-node @opentelemetry/sdk-trace-base @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/exporter-trace-otlp-grpc +``` + +## Instrument the crawler + +OpenTelemetry instrumentation must be set up **before** importing Crawlee or any other instrumented modules. The easiest way to do this is to create a separate setup file and import it first using Node.js's `--import` flag. + +### Module hook + +Crawlee is published as ECMAScript modules, so the automatic instrumentation can only patch the crawler classes through +Node's module hook. Register it in its own file, which is preloaded ahead of everything else: + + + {RegisterHookSource} + + +### Setup file + +Create a setup file that initializes OpenTelemetry with the Crawlee instrumentation. Because the exporters buffer +data, the setup file is also where the SDK is shut down, so that everything is flushed before the process exits: + + + {SetupSource} + + +### Main crawler file + +Now create your crawler. The `CrawleeInstrumentation` will automatically instrument the core crawler methods: + + + {BasicExampleSource} + + +### Run the crawler + +Run your crawler with the setup file imported first: + +```bash +npx tsx --import ./src/register-hook.ts --import ./src/setup.ts ./src/main.ts +``` + +The `--import` flags run in order, before any of your own code: the hook is installed first, then the OpenTelemetry SDK +starts, and only then is the crawler loaded and patched. + +The examples on this page live in the Crawlee repository, so to run this one from a checkout, from the repository root: + +```bash +pnpm exec tsx --import ./docs/guides/trace_and_monitor_register_hook.ts \ + --import ./docs/guides/trace_and_monitor_setup.ts \ + ./docs/guides/trace_and_monitor_basic.ts +``` + +## Troubleshoot instrumentation setup + +Proper setup of instrumentation depends on your specific environment setup. Please refer to the [OTEL documentation](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md). + + +## Analyze the results + +In the Jaeger UI, you can search for different traces, apply filtering, compare traces, view their detailed attributes, view timing details, and more. For a detailed description of the tool's capabilities, please refer to the [Jaeger documentation](https://www.jaegertracing.io/docs/latest/). + +![Jaeger search view](/img/jaeger-search.png) + +## Customize the instrumentation + +The `CrawleeInstrumentation` class provides several configuration options to customize what gets instrumented: + +| Option | Default | Description | +|--------|---------|-------------| +| `enabled` | `true` | Enable or disable the instrumentation entirely | +| `requestHandlingInstrumentation` | `true` | Instrument the core request handling methods of the crawlers | +| `logInstrumentation` | `true` | Forward Crawlee logs to OpenTelemetry logs | +| `customInstrumentation` | `[]` | Array of custom class methods to instrument | + +### Configuration example + +```ts +import { CrawleeInstrumentation } from '@crawlee/otel'; + +const crawleeInstrumentation = new CrawleeInstrumentation({ + // Disable automatic request handling instrumentation + requestHandlingInstrumentation: false, + // Disable log forwarding + logInstrumentation: false, + // Add custom instrumentation + customInstrumentation: [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'my-custom-span-name', + }, + ], +}); +``` + +## Manual span instrumentation with wrapWithSpan + +For more fine-grained control, you can use the `wrapWithSpan` utility to wrap specific functions with OpenTelemetry spans. This is particularly useful for instrumenting request handlers, hooks, and error handlers. + + + {WrapWithSpanSource} + + +### wrapWithSpan options + +The `wrapWithSpan` function accepts these options: + +| Option | Type | Description | +|--------|------|-------------| +| `spanName` | `string \| ((...args) => string)` | Static name or function that receives the handler arguments and returns a span name | +| `spanOptions` | `SpanOptions \| ((...args) => SpanOptions)` | Static options or function that returns OpenTelemetry SpanOptions including attributes | +| `tracer` | `Tracer` | Custom tracer instance. Defaults to the tracer of the registered `CrawleeInstrumentation`, or to a tracer from the global provider when no instrumentation is registered. | + +### Accessing the current span + +Inside a wrapped function, you can access the current span to add additional attributes or events: + +```ts +import { context, trace } from '@opentelemetry/api'; + +requestHandler: wrapWithSpan( + async ({ request, $ }) => { + const span = trace.getSpan(context.active()); + + const title = $('title').text(); + + if (span) { + span.setAttribute('page.title', title); + span.addEvent('page_scraped', { url: request.url }); + } + + // ... rest of your handler + }, + { spanName: 'request-handler' } +), +``` + +## Custom class instrumentation + +You can also create your instrumentation by selecting only the methods you want to instrument. Here's an example of adding custom instrumentation for specific crawler methods: + + + {CustomInstrumentationSource} + + +## What gets instrumented automatically + +When `requestHandlingInstrumentation` is enabled (the default), the following methods are automatically instrumented: + +| Crawler | Method | Span Name | +|---------|--------|-----------| +| `BasicCrawler` | `run` | `crawlee.crawler.run` | +| `BasicCrawler` | `handleRequest` | `crawlee.crawler.handleRequest` | +| `BasicCrawler` | `runRequestHandler` | `crawlee.crawler.runRequestHandler` | +| `BasicCrawler` | `requestFunctionErrorHandler` | `crawlee.crawler.requestFunctionErrorHandler` | +| `BasicCrawler` | `handleFailedRequestHandler` | `crawlee.crawler.handleFailedRequestHandler` | +| `HttpCrawler` | `makeHttpRequest` | `crawlee.http.makeHttpRequest` | +| `BrowserCrawler` | `navigate` | `crawlee.browser.navigate` | +| `AdaptivePlaywrightCrawler` | `runRequestHandler` | `crawlee.crawler.runRequestHandler` | + +`crawlee.http.makeHttpRequest` and `crawlee.browser.navigate` are recorded as client spans, since they are the calls +that leave your process. The rest are internal spans. + +Every crawler inherits the `BasicCrawler` methods, so the table covers all of them. `AdaptivePlaywrightCrawler` is +listed separately only because it replaces `runRequestHandler` with its own implementation, which is instrumented in +its place - a run of it still produces one `crawlee.crawler.runRequestHandler` span per request. + +Every automatically instrumented span carries the `code.function.name` attribute - spans you create yourself with +`wrapWithSpan` carry only the attributes you give them. The `crawlee.crawler.run` span additionally carries +`crawlee.crawler.type` with the class name of the crawler that is running, and spans of the methods that receive a +crawling context (the request handlers, navigation handlers and error handlers) also include: + +- `url.full` - the request URL +- `http.request.method` - the request method +- `crawlee.request.id` - the Crawlee request ID +- `crawlee.request.retry_count` - how many times the request has been retried + +`url.full` and `http.request.method` are the stable [OpenTelemetry semantic conventions](https://opentelemetry.io/docs/specs/semconv/), +so traces stay comparable with the rest of your instrumented stack. Crawlee-specific data that has no semantic +convention keeps the `crawlee.` prefix. + +## Forwarded logs + +With `logInstrumentation` enabled (the default), Crawlee logs are emitted as OpenTelemetry log records. The Crawlee log +level is mapped onto the OpenTelemetry severity (`SOFT_FAIL` and `WARNING` both become `WARN`, `PERF` becomes `DEBUG`), +the structured `data` of the log call becomes the log record attributes, and any `Error` in it is recorded as the +`exception.type`, `exception.message` and `exception.stacktrace` attributes. + +This works for whichever logger you configure. The instrumentation patches the logging methods Crawlee derives in +`BaseCrawleeLogger`, so a Winston, Pino or hand-written adapter is forwarded just like the default one. + +Crawlee leaves level filtering to the underlying logging library, so every message is forwarded regardless of the +configured log level - filter them in your OpenTelemetry pipeline instead. + +The record body is the message as it was passed to the log call, not the line the logger prints: a `perf` record has no +`[PERF]` prefix, and an `exception` record carries the message on its own with the error in the `exception.*` +attributes instead of appended to it. Match the two by attribute rather than by grepping for the printed line. + +:::caution Jaeger does not accept OpenTelemetry logs + +The records only go somewhere once you add a log record processor to the SDK, and the backend has to implement the +OTLP logs service. Jaeger is a tracing backend and does not - pointing a log exporter at the `jaegertracing/all-in-one` +container above makes every log batch fail with +`UNIMPLEMENTED: unknown service opentelemetry.proto.collector.logs.v1.LogsService`. Send the logs to an +[OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) or a backend that ingests them instead. + +::: + +To export the logs, install `@opentelemetry/sdk-logs` along with a log exporter and add a log record processor to the +setup file: + +```ts title="src/setup.ts" +import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc'; +import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs'; + +export const sdk = new NodeSDK({ + // ... the trace configuration from above + logRecordProcessors: [ + new BatchLogRecordProcessor(new OTLPLogExporter({ url: 'http://localhost:4317' })), + ], +}); +``` + +Set `logInstrumentation: false` if you would rather keep the Crawlee logs out of OpenTelemetry entirely. + diff --git a/docs/guides/trace_and_monitor_basic.ts b/docs/guides/trace_and_monitor_basic.ts new file mode 100644 index 000000000000..eba24f7b6ea8 --- /dev/null +++ b/docs/guides/trace_and_monitor_basic.ts @@ -0,0 +1,19 @@ +import { CheerioCrawler } from 'crawlee'; + +const crawler = new CheerioCrawler({ + maxRequestsPerCrawl: 10, + + async requestHandler({ request, $, enqueueLinks, log }) { + const title = $('title').text(); + log.info(`Crawled ${request.url}`, { title }); + + await enqueueLinks({ + include: ['https://crawlee.dev/**'], + }); + }, +}); + +await crawler.run(['https://crawlee.dev']); + +// The setup file flushes the telemetry on exit. +console.log('Crawl complete. View traces at http://localhost:16686'); diff --git a/docs/guides/trace_and_monitor_custom.ts b/docs/guides/trace_and_monitor_custom.ts new file mode 100644 index 000000000000..4b51f2245f40 --- /dev/null +++ b/docs/guides/trace_and_monitor_custom.ts @@ -0,0 +1,78 @@ +import { CrawleeInstrumentation } from '@crawlee/otel'; +import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; +import { resourceFromAttributes } from '@opentelemetry/resources'; +import { NodeSDK } from '@opentelemetry/sdk-node'; +import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { ATTR_HTTP_REQUEST_METHOD, ATTR_SERVICE_NAME, ATTR_URL_FULL } from '@opentelemetry/semantic-conventions'; + +const crawleeInstrumentation = new CrawleeInstrumentation({ + // Disable default request handling instrumentation + requestHandlingInstrumentation: false, + // Disable log forwarding to OpenTelemetry + logInstrumentation: false, + // Define custom methods to instrument + customInstrumentation: [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'crawler.run', + spanOptions() { + return { + attributes: { + 'crawler.type': this.constructor.name, + }, + }; + }, + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'runRequestHandler', + // Dynamic span name using the context argument + spanName(context: any) { + return `request ${context.request.url}`; + }, + spanOptions(context: any) { + return { + attributes: { + [ATTR_URL_FULL]: context.request.url, + [ATTR_HTTP_REQUEST_METHOD]: context.request.method, + }, + }; + }, + }, + ], +}); + +const resource = resourceFromAttributes({ + [ATTR_SERVICE_NAME]: 'custom-instrumented-crawler', +}); + +const traceExporter = new OTLPTraceExporter({ + url: 'http://localhost:4317', +}); + +export const sdk = new NodeSDK({ + resource, + spanProcessors: [new BatchSpanProcessor(traceExporter)], + instrumentations: [crawleeInstrumentation], +}); + +sdk.start(); + +// Like the setup file above, this one is preloaded before the crawler, so it also owns flushing the buffered +// telemetry on the way out - without this the batched spans are dropped when the process exits. +const shutdown = async () => { + await sdk.shutdown(); +}; + +// `beforeExit` covers a script that simply runs to completion... +process.once('beforeExit', () => { + void shutdown(); +}); + +// ...while signals have to be handled separately, as they do not emit `beforeExit`. +process.once('SIGTERM', () => { + void shutdown().then(() => process.exit(0)); +}); diff --git a/docs/guides/trace_and_monitor_register_hook.ts b/docs/guides/trace_and_monitor_register_hook.ts new file mode 100644 index 000000000000..57cdbd493a44 --- /dev/null +++ b/docs/guides/trace_and_monitor_register_hook.ts @@ -0,0 +1,6 @@ +import { register } from 'node:module'; +import { pathToFileURL } from 'node:url'; + +// Installs the OpenTelemetry module hook, which the automatic instrumentation needs in order to patch the Crawlee +// classes as they are imported. This file must be preloaded before the OpenTelemetry setup and before the crawler. +register('@opentelemetry/instrumentation/hook.mjs', pathToFileURL('./')); diff --git a/docs/guides/trace_and_monitor_setup.ts b/docs/guides/trace_and_monitor_setup.ts new file mode 100644 index 000000000000..09159363b8cc --- /dev/null +++ b/docs/guides/trace_and_monitor_setup.ts @@ -0,0 +1,59 @@ +import { CrawleeInstrumentation } from '@crawlee/otel'; +import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; +import { resourceFromAttributes } from '@opentelemetry/resources'; +import { NodeSDK } from '@opentelemetry/sdk-node'; +import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'; + +// Create a resource that identifies your service +const resource = resourceFromAttributes({ + [ATTR_SERVICE_NAME]: 'my-crawler', + [ATTR_SERVICE_VERSION]: '1.0.0', + 'deployment.environment': 'development', +}); + +// Configure exporters to send data to Jaeger via OTLP +// The gRPC exporter takes the collector endpoint without a signal path - unlike the HTTP one, +// which would use `http://localhost:4318/v1/traces`. +const traceExporter = new OTLPTraceExporter({ + url: 'http://localhost:4317', +}); + +// Create the Crawlee instrumentation +const crawleeInstrumentation = new CrawleeInstrumentation(); + +// Initialize the OpenTelemetry SDK +export const sdk = new NodeSDK({ + resource, + spanProcessors: [new BatchSpanProcessor(traceExporter)], + instrumentations: [crawleeInstrumentation], +}); + +// Start the SDK +sdk.start(); + +console.log('OpenTelemetry initialized'); + +// This file is preloaded before the crawler, so it also owns flushing the buffered telemetry on the way out. +let shuttingDown: Promise | undefined; + +const shutdown = () => { + // Every handler below can fire, and the SDK must only be shut down once. + shuttingDown ??= sdk.shutdown(); + return shuttingDown; +}; + +// `beforeExit` covers a script that simply runs to completion. The flush it starts is async work, so Node keeps the +// process alive for it and then fires `beforeExit` once more - hence `on` rather than `once`, and hence `shutdown` +// having to be idempotent. +process.on('beforeExit', () => { + void shutdown(); +}); + +// Signals have to be handled separately, as they do not emit `beforeExit`. `SIGINT` is the one you send by pressing +// Ctrl-C, so without it a local run loses whatever the exporter had not sent yet. +for (const signal of ['SIGINT', 'SIGTERM'] as const) { + process.once(signal, () => { + void shutdown().then(() => process.exit(0)); + }); +} diff --git a/docs/guides/trace_and_monitor_wrap_with_span.ts b/docs/guides/trace_and_monitor_wrap_with_span.ts new file mode 100644 index 000000000000..ffe342a5f845 --- /dev/null +++ b/docs/guides/trace_and_monitor_wrap_with_span.ts @@ -0,0 +1,87 @@ +import { wrapWithSpan } from '@crawlee/otel'; +import { context, trace } from '@opentelemetry/api'; +import { ATTR_EXCEPTION_MESSAGE, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from '@opentelemetry/semantic-conventions'; +import type { CheerioCrawlingContext, CrawlingContext } from 'crawlee'; +import { CheerioCrawler } from 'crawlee'; + +const crawler = new CheerioCrawler({ + maxRequestsPerCrawl: 10, + + // Wrap the request handler with a custom span + requestHandler: wrapWithSpan( + async ({ request, $, enqueueLinks, log }: CheerioCrawlingContext) => { + // Access the current span to add custom attributes + const span = trace.getSpan(context.active()); + + const title = $('title').text(); + const headings = $('h1, h2').length; + const links = $('a').length; + + if (span) { + span.setAttribute('page.title', title); + span.setAttribute('page.headings_count', headings); + span.setAttribute('page.links_count', links); + } + + log.info(`Scraped page`, { url: request.url, title }); + + await enqueueLinks({ + include: ['https://crawlee.dev/**'], + }); + }, + { + // Dynamic span name based on the request + spanName: ({ request }: CheerioCrawlingContext) => `scrape ${request.url}`, + // Add attributes to the span + spanOptions: ({ request }: CheerioCrawlingContext) => ({ + attributes: { + [ATTR_URL_FULL]: request.url, + [ATTR_HTTP_REQUEST_METHOD]: request.method, + }, + }), + }, + ), + + // Wrap hooks with spans + preNavigationHooks: [ + wrapWithSpan( + ({ log }: CheerioCrawlingContext) => { + log.debug('Pre-navigation hook executed'); + }, + { + spanName: 'pre-navigation-hook', + }, + ), + ], + + // Wrap error handlers + errorHandler: wrapWithSpan( + ({ request, log }: CrawlingContext, error: Error) => { + log.error(`Request failed: ${request.url}`, { + error: error.message, + }); + }, + { + spanName: ({ request }: CrawlingContext) => `error-handler ${request.url}`, + spanOptions: ({ request }: CrawlingContext, error: Error) => ({ + attributes: { + [ATTR_URL_FULL]: request.url, + [ATTR_EXCEPTION_MESSAGE]: error.message, + }, + }), + }, + ), + + failedRequestHandler: wrapWithSpan( + ({ request, log }: CrawlingContext, error: Error) => { + log.error(`Request permanently failed: ${request.url}`, { + error: error.message, + }); + }, + { + spanName: 'failed-request-handler', + }, + ), +}); + +await crawler.run(['https://crawlee.dev']); diff --git a/docs/package.json b/docs/package.json index 5e9c57042805..f028fef954e5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -14,7 +14,14 @@ "@crawlee/got-scraping-client": "workspace:*", "@crawlee/http-client": "workspace:*", "@crawlee/impit-client": "workspace:*", + "@crawlee/otel": "workspace:*", "@crawlee/stagehand": "workspace:*", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/exporter-trace-otlp-grpc": "^0.210.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-node": "^0.210.0", + "@opentelemetry/sdk-trace-base": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.39.0", "apify": "*", "crawlee": "workspace:*", "impit": "^0.14.2", diff --git a/docs/public-api/crawlee-otel.api.md b/docs/public-api/crawlee-otel.api.md new file mode 100644 index 000000000000..08f1e1296b77 --- /dev/null +++ b/docs/public-api/crawlee-otel.api.md @@ -0,0 +1,50 @@ +## Public API Report File for "@crawlee/otel" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { InstrumentationBase } from '@opentelemetry/instrumentation'; +import type { InstrumentationConfig } from '@opentelemetry/instrumentation'; +import type { InstrumentationModuleDefinition } from '@opentelemetry/instrumentation'; +import type { SpanOptions } from '@opentelemetry/api'; +import type { Tracer } from '@opentelemetry/api'; +import type { TracerProvider } from '@opentelemetry/api'; + +// @public +export interface ClassMethodToInstrument { + className: string; + methodName: string; + moduleName: string; + spanName?: string | ((this: any, ...args: any[]) => string); + spanOptions?: SpanOptions | ((this: any, ...args: any[]) => SpanOptions); +} + +// @public (undocumented) +export class CrawleeInstrumentation extends InstrumentationBase { + constructor(config?: CrawleeInstrumentationConfig); + // (undocumented) + protected init(): InstrumentationModuleDefinition[]; + setTracerProvider(tracerProvider: TracerProvider): void; +} + +// @public (undocumented) +export interface CrawleeInstrumentationConfig extends InstrumentationConfig { + // (undocumented) + customInstrumentation?: ClassMethodToInstrument[]; + // (undocumented) + logInstrumentation?: boolean; + // (undocumented) + requestHandlingInstrumentation?: boolean; +} + +// @public +export function wrapWithSpan(fn: (...args: Args) => Return, options?: { + spanName?: string | ((...args: Args) => string); + spanOptions?: SpanOptions | ((...args: Args) => SpanOptions); + tracer?: Tracer; +}): (...args: Args) => Return; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/package.json b/package.json index 9f26609e17f9..2023d31f0fef 100644 --- a/package.json +++ b/package.json @@ -69,11 +69,20 @@ "@crawlee/impit-client": "workspace:*", "@crawlee/jsdom": "workspace:*", "@crawlee/linkedom": "workspace:*", + "@crawlee/otel": "workspace:*", "@crawlee/playwright": "workspace:*", "@crawlee/puppeteer": "workspace:*", "@crawlee/stagehand": "workspace:*", "@crawlee/types": "workspace:*", "@crawlee/utils": "workspace:*", + "@microsoft/api-extractor": "^7.58.9", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/api-logs": "^0.210.0", + "@opentelemetry/instrumentation": "^0.210.0", + "@opentelemetry/sdk-logs": "^0.210.0", + "@opentelemetry/sdk-trace-base": "^2.0.0", + "@opentelemetry/sdk-trace-node": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.39.0", "@oxlint/plugins": "^1.62.0", "@playwright/browser-chromium": "1.61.1", "@playwright/browser-firefox": "1.61.1", diff --git a/packages/basic-crawler/src/internals/basic-crawler.ts b/packages/basic-crawler/src/internals/basic-crawler.ts index 618f41e302c2..d6774f247b71 100644 --- a/packages/basic-crawler/src/internals/basic-crawler.ts +++ b/packages/basic-crawler/src/internals/basic-crawler.ts @@ -59,7 +59,6 @@ import { getObjectType, KeyValueStore, log, - LogLevel, mergeCookies, MissingSessionError, NavigationSkippedError, @@ -1622,7 +1621,11 @@ export class BasicCrawler< setStatusMessage(message: string, options: SetStatusMessageOptions = {}) { const data = options.isStatusMessageTerminal != null ? { terminal: options.isStatusMessageTerminal } : undefined; - this.log.logWithLevel(LogLevel[(options.level as 'DEBUG') ?? 'DEBUG'], message, data); + // Each allowed level has its own method on the logger, so this goes through them rather than through + // `logWithLevel`, which is abstract and therefore cannot be instrumented. + this.log[ + ({ DEBUG: 'debug', INFO: 'info', WARNING: 'warning', ERROR: 'error' } as const)[options.level ?? 'DEBUG'] + ](message, data); // Broadcast the status message through the event system. Consumers (e.g. the Apify SDK) can // subscribe to `EventType.STATUS_MESSAGE` and propagate it to their status-reporting backend. diff --git a/packages/otel/.npmignore b/packages/otel/.npmignore new file mode 100644 index 000000000000..d18b05a66a6a --- /dev/null +++ b/packages/otel/.npmignore @@ -0,0 +1,5 @@ +node_modules +src +test +coverage +tsconfig.* diff --git a/packages/otel/CHANGELOG.md b/packages/otel/CHANGELOG.md new file mode 100644 index 000000000000..e9fb6ecf5930 --- /dev/null +++ b/packages/otel/CHANGELOG.md @@ -0,0 +1,4 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. \ No newline at end of file diff --git a/packages/otel/README.md b/packages/otel/README.md new file mode 100644 index 000000000000..09e3bd5eb353 --- /dev/null +++ b/packages/otel/README.md @@ -0,0 +1,81 @@ +# @crawlee/otel + +This package provides [OpenTelemetry](https://opentelemetry.io/) instrumentation for Crawlee. It traces the request +handling pipeline of the crawlers and forwards Crawlee logs to OpenTelemetry, so you can analyze crawler runs in any +OpenTelemetry-compatible backend (Jaeger, Zipkin, Signoz, ...). + +## Installation + +The OpenTelemetry API packages are peer dependencies, so install them alongside this package: + +```bash +npm install @crawlee/otel @opentelemetry/api @opentelemetry/api-logs @opentelemetry/sdk-node +``` + +## Example usage + +Crawlee is published as ECMAScript modules, so the crawler classes can only be patched through Node's module hook. +Register it in its own file, preloaded ahead of everything else: + +```typescript +// register-hook.ts +import { register } from 'node:module'; +import { pathToFileURL } from 'node:url'; + +register('@opentelemetry/instrumentation/hook.mjs', pathToFileURL('./')); +``` + +Then configure the SDK in a setup file, which also has to load before Crawlee: + +```typescript +// setup.ts +import { CrawleeInstrumentation } from '@crawlee/otel'; +import { NodeSDK } from '@opentelemetry/sdk-node'; + +export const sdk = new NodeSDK({ + instrumentations: [new CrawleeInstrumentation()], + // ... exporters and resource configuration +}); + +sdk.start(); +``` + +```bash +node --import ./register-hook.js --import ./setup.js ./main.js +``` + +Without the hook the crawler runs normally but no spans are produced. Register it with `register()` from a preloaded +file as shown - `--experimental-loader=@opentelemetry/instrumentation/hook.mjs` patches the classes but the spans do +not come out the other end. + +Spans for `BasicCrawler`, `HttpCrawler` and `BrowserCrawler` request handling are then created automatically. + +## Instrumenting your own handlers + +Use `wrapWithSpan` to put your own code on the trace. The span name and attributes can be derived from the arguments +the wrapped function receives: + +```typescript +import { CheerioCrawler } from '@crawlee/cheerio'; +import { wrapWithSpan } from '@crawlee/otel'; +import { context, trace } from '@opentelemetry/api'; + +const crawler = new CheerioCrawler({ + requestHandler: wrapWithSpan( + async ({ request, $ }) => { + trace.getSpan(context.active())?.setAttribute('page.title', $('title').text()); + }, + { spanName: ({ request }) => `scrape ${request.url}` }, + ), +}); +``` + +## Configuration + +| Option | Default | Description | +| --- | --- | --- | +| `requestHandlingInstrumentation` | `true` | Instrument the core request handling methods of the crawlers. | +| `logInstrumentation` | `true` | Forward Crawlee logs to OpenTelemetry logs. | +| `customInstrumentation` | `[]` | Additional `@crawlee/*` class methods to instrument. | + +> This package is part of the [Crawlee](https://crawlee.dev) monorepo. diff --git a/packages/otel/package.json b/packages/otel/package.json new file mode 100644 index 000000000000..2cf08a344e67 --- /dev/null +++ b/packages/otel/package.json @@ -0,0 +1,56 @@ +{ + "name": "@crawlee/otel", + "version": "4.0.0", + "description": "OpenTelemetry instrumentation for Crawlee", + "engines": { + "node": ">=22.0.0" + }, + "type": "module", + "exports": { + ".": "./dist/index.js", + "./package.json": "./package.json" + }, + "keywords": [ + "apify", + "api", + "otel", + "opentelemetry" + ], + "author": { + "name": "Apify", + "email": "support@apify.com", + "url": "https://apify.com" + }, + "contributors": [], + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/apify/crawlee" + }, + "bugs": { + "url": "https://github.com/apify/crawlee/issues" + }, + "homepage": "https://crawlee.dev", + "scripts": { + "build": "pnpm clean && pnpm compile && pnpm copy", + "clean": "rimraf ./dist", + "compile": "tsc -p tsconfig.build.json", + "copy": "tsx ../../scripts/copy.ts" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@opentelemetry/instrumentation": "^0.210.0", + "@opentelemetry/semantic-conventions": "^1.39.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0", + "@opentelemetry/api-logs": "^0.210.0" + }, + "devDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/api-logs": "^0.210.0", + "semver": "^7.7.0" + } +} diff --git a/packages/otel/src/constants.ts b/packages/otel/src/constants.ts new file mode 100644 index 000000000000..fa2dca65a703 --- /dev/null +++ b/packages/otel/src/constants.ts @@ -0,0 +1,214 @@ +import type { Attributes } from '@opentelemetry/api'; +import { SpanKind } from '@opentelemetry/api'; +import { SeverityNumber } from '@opentelemetry/api-logs'; +import { ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from '@opentelemetry/semantic-conventions'; + +import type { CrawlingContextLike, LoggerMethodDefinition } from './internal-types.js'; +import type { ClassMethodToInstrument, CrawleeInstrumentationConfig } from './types.js'; + +export const PACKAGE_NAME = '@crawlee/otel'; + +/** Used when the package version cannot be determined at runtime. */ +export const UNKNOWN_PACKAGE_VERSION = '0.0.0'; + +/** + * Versions of the instrumented Crawlee packages this instrumentation knows how to patch. Methods that are missing + * in the resolved version are skipped with a warning instead of breaking the module load. + * + * Spelled out rather than written as `^4.0.0`, because a caret range never matches a prerelease and every published + * Crawlee v4 is one (`4.0.0-beta.x`, `4.0.0-rc.x`). The explicit `-0` bounds admit prereleases of 4.0.0 itself, and + * `includePrerelease` on the module definitions extends that to prereleases of later v4 minors. + * + * `@opentelemetry/instrumentation` only consults this when the loader hands it the module's base directory, which the + * ESM hook does not do - so today a wrong range here would not stop anything from being patched. It is still declared + * correctly rather than left as documentation: the range is what decides whether a module is patched as soon as a base + * directory is available, and being silently skipped is not a failure mode worth leaving armed. + */ +export const SUPPORTED_CRAWLEE_VERSIONS = ['>=4.0.0-0 <5.0.0-0']; + +export const baseConfig: CrawleeInstrumentationConfig = { + enabled: true, + requestHandlingInstrumentation: true, + logInstrumentation: true, + customInstrumentation: [], +} as const; + +/** + * Extracts span attributes from a Crawlee crawling context. Uses the stable OpenTelemetry semantic conventions where + * they exist, so that traces stay comparable with other instrumented HTTP clients. + */ +function requestAttributes(crawlingContext: CrawlingContextLike | undefined): Attributes { + const request = crawlingContext?.request; + + // The context shape depends on the installed Crawlee version, so never assume the request is there. + if (!request) { + return {}; + } + + return { + 'crawlee.request.id': request.id, + [ATTR_URL_FULL]: request.url, + [ATTR_HTTP_REQUEST_METHOD]: request.method, + 'crawlee.request.retry_count': request.retryCount, + }; +} + +export const requestHandlingInstrumentationMethods: ClassMethodToInstrument[] = [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'crawlee.crawler.run', + spanOptions() { + return { + attributes: { + 'crawlee.crawler.type': this.constructor.name, + }, + }; + }, + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'handleRequest', + spanName: 'crawlee.crawler.handleRequest', + // `handleRequest(crawlingContext, requestSource, request)` + spanOptions(crawlingContext: CrawlingContextLike) { + return { attributes: requestAttributes(crawlingContext) }; + }, + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'runRequestHandler', + spanName: 'crawlee.crawler.runRequestHandler', + spanOptions(crawlingContext: CrawlingContextLike) { + return { attributes: requestAttributes(crawlingContext) }; + }, + }, + { + // `AdaptivePlaywrightCrawler` replaces `runRequestHandler` outright instead of calling `super`, so the + // `BasicCrawler` patch above never fires for it. `BrowserCrawler` does call `super`, which is why it needs + // no entry of its own. + moduleName: '@crawlee/playwright', + className: 'AdaptivePlaywrightCrawler', + methodName: 'runRequestHandler', + spanName: 'crawlee.crawler.runRequestHandler', + spanOptions(crawlingContext: CrawlingContextLike) { + return { attributes: requestAttributes(crawlingContext) }; + }, + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'requestFunctionErrorHandler', + spanName: 'crawlee.crawler.requestFunctionErrorHandler', + // `requestFunctionErrorHandler(error, crawlingContext, request, source)` + spanOptions(_error: Error, crawlingContext: CrawlingContextLike) { + return { attributes: requestAttributes(crawlingContext) }; + }, + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'handleFailedRequestHandler', + spanName: 'crawlee.crawler.handleFailedRequestHandler', + spanOptions(crawlingContext: CrawlingContextLike) { + return { attributes: requestAttributes(crawlingContext) }; + }, + }, + { + moduleName: '@crawlee/http', + className: 'HttpCrawler', + methodName: 'makeHttpRequest', + spanName: 'crawlee.http.makeHttpRequest', + spanOptions(crawlingContext: CrawlingContextLike) { + // An outbound HTTP call, so a client span rather than the default internal one. + return { kind: SpanKind.CLIENT, attributes: requestAttributes(crawlingContext) }; + }, + }, + { + moduleName: '@crawlee/browser', + className: 'BrowserCrawler', + methodName: 'navigate', + spanName: 'crawlee.browser.navigate', + spanOptions(crawlingContext: CrawlingContextLike) { + // The browser navigation is the outbound call here. + return { kind: SpanKind.CLIENT, attributes: requestAttributes(crawlingContext) }; + }, + }, +] as const; + +/** + * Maps Apify log levels to OpenTelemetry severity numbers. + * See https://github.com/apify/apify-shared-js/blob/83d46cf72a338ff671f89dcbc2b0db7dd571e29f/packages/log/src/log_consts.ts#L1 + * + * ```typescript + * export enum LogLevel { + * // Turns off logging completely + * OFF = 0, + * // For unexpected errors in Apify system + * ERROR = 1 = SeverityNumber.ERROR, + * // For situations where error is caused by user (e.g. Meteor.Error), i.e. when the error is not + * // caused by Apify system, avoid the word "ERROR" to simplify searching in log + * SOFT_FAIL = 2 = SeverityNumber.WARN, + * WARNING = 3 = SeverityNumber.WARN, + * INFO = 4 = SeverityNumber.INFO, + * DEBUG = 5 = SeverityNumber.DEBUG, + * // for performance stats + * PERF = 6 = SeverityNumber.DEBUG, + * } + * ``` + */ +export const apifyLogLevelMap: Record = { + 1: SeverityNumber.ERROR, + 2: SeverityNumber.WARN, + 3: SeverityNumber.WARN, + 4: SeverityNumber.INFO, + 5: SeverityNumber.DEBUG, + 6: SeverityNumber.DEBUG, +} as const; + +/** Human readable Apify log level names, emitted as the `severityText` of the forwarded log records. */ +export const apifyLogLevelNameMap: Record = { + 1: 'ERROR', + 2: 'SOFT_FAIL', + 3: 'WARNING', + 4: 'INFO', + 5: 'DEBUG', + 6: 'PERF', +} as const; + +/** + * The logging methods to instrument, with the level each logs at. + * + * These live on `BaseCrawleeLogger.prototype`, which every Crawlee logger derives from, so patching them forwards logs + * from any logger implementation - the default Apify one as well as a Winston, Pino or hand-written adapter. Each of + * them dispatches straight to the abstract `logWithLevel`, which the adapter implements, so a call is only seen once. + * `warningOnce` and `deprecated` are covered through `warning`. + */ +export const loggerMethods: LoggerMethodDefinition[] = [ + { methodName: 'error', level: 1, read: (args) => readMessageAndData(args) }, + { + methodName: 'exception', + level: 1, + // `exception(exception, message, data)` - the error comes first. + read: (args) => ({ + message: String(args[1] ?? ''), + data: { ...(args[2] as Record | undefined), exception: args[0] }, + }), + }, + { methodName: 'softFail', level: 2, read: (args) => readMessageAndData(args) }, + { methodName: 'warning', level: 3, read: (args) => readMessageAndData(args) }, + { methodName: 'info', level: 4, read: (args) => readMessageAndData(args) }, + { methodName: 'debug', level: 5, read: (args) => readMessageAndData(args) }, + { methodName: 'perf', level: 6, read: (args) => readMessageAndData(args) }, +]; + +/** The shape shared by every logging method except `exception`: `(message, data?)`. */ +function readMessageAndData(args: unknown[]) { + return { + message: String(args[0] ?? ''), + data: args[1] as Record | undefined, + }; +} diff --git a/packages/otel/src/index.ts b/packages/otel/src/index.ts new file mode 100644 index 000000000000..5b04f3c8abcb --- /dev/null +++ b/packages/otel/src/index.ts @@ -0,0 +1,3 @@ +export { CrawleeInstrumentation } from './instrumentation.js'; +export type * from './types.js'; +export { wrapWithSpan } from './wrapWithSpan.js'; diff --git a/packages/otel/src/instrumentation.ts b/packages/otel/src/instrumentation.ts new file mode 100644 index 000000000000..12d42548bd44 --- /dev/null +++ b/packages/otel/src/instrumentation.ts @@ -0,0 +1,227 @@ +// oxlint-disable no-underscore-dangle -- `_wrap`, `_unwrap` and `_diag` are inherited from `InstrumentationBase`. +import type { SpanOptions, TracerProvider } from '@opentelemetry/api'; +import { SeverityNumber } from '@opentelemetry/api-logs'; +import type { InstrumentationModuleDefinition } from '@opentelemetry/instrumentation'; +import { InstrumentationBase, InstrumentationNodeModuleDefinition, isWrapped } from '@opentelemetry/instrumentation'; +import { ATTR_CODE_FUNCTION_NAME } from '@opentelemetry/semantic-conventions'; + +import { + apifyLogLevelMap, + apifyLogLevelNameMap, + baseConfig, + loggerMethods, + PACKAGE_NAME, + requestHandlingInstrumentationMethods, + SUPPORTED_CRAWLEE_VERSIONS, +} from './constants.js'; +import type { ClassMethodPatchDefinition, LoggerMethodDefinition, ModuleDefinition } from './internal-types.js'; +import type { CrawleeInstrumentationConfig } from './types.js'; +import { buildLogAttributes, buildModuleDefinitions, getPackageVersion } from './utilities.js'; +import { resolveSpanName, resolveSpanOptions, setSharedTracer, wrapWithSpan } from './wrapWithSpan.js'; + +/** + * Builds a module definition for one of the instrumented Crawlee packages. + * + * `InstrumentationNodeModuleDefinition` does not take `includePrerelease` through its constructor, but + * `InstrumentationBase` reads it off the definition when it decides whether to patch a resolved module version, so it + * is set here. Without it, {@link SUPPORTED_CRAWLEE_VERSIONS} would only cover prereleases of `4.0.0` and every + * `4.x.0-beta` would go uninstrumented. + */ +function crawleeModuleDefinition( + moduleName: string, + patch: (moduleExports: any) => any, + unpatch: (moduleExports: any) => any, +): InstrumentationModuleDefinition { + const definition: InstrumentationModuleDefinition = new InstrumentationNodeModuleDefinition( + moduleName, + SUPPORTED_CRAWLEE_VERSIONS, + patch, + unpatch, + ); + definition.includePrerelease = true; + return definition; +} + +export class CrawleeInstrumentation extends InstrumentationBase { + constructor(config: CrawleeInstrumentationConfig = {}) { + // Each flag is resolved on its own rather than by spreading `config` over `baseConfig`: a spread lets an + // explicit `undefined` - which is what `{ logInstrumentation: options.logs }` produces when `options.logs` + // is not set - overwrite the default with nothing and quietly disable the feature. + super(PACKAGE_NAME, getPackageVersion(), { + ...config, + enabled: config.enabled ?? baseConfig.enabled, + requestHandlingInstrumentation: + config.requestHandlingInstrumentation ?? baseConfig.requestHandlingInstrumentation, + logInstrumentation: config.logInstrumentation ?? baseConfig.logInstrumentation, + customInstrumentation: config.customInstrumentation ?? baseConfig.customInstrumentation, + }); + } + + /** + * Shares the tracer with the exported `wrapWithSpan` helper, so that manually wrapped handlers end up in the same + * instrumentation scope as the automatic spans. + * + * This has to happen here rather than in the constructor. The constructor can only reach the tracer of the global + * API, and that is not necessarily the one this instrumentation ends up using - a `tracerProvider` passed to + * `registerInstrumentations` is never registered globally, and a duplicated `@opentelemetry/api` in the dependency + * tree has its own global. Handing over a tracer from the wrong provider silences every span, including the + * automatic ones, and because it is not `undefined` it also shadows the fallback in `wrapWithSpan`. + */ + public override setTracerProvider(tracerProvider: TracerProvider): void { + super.setTracerProvider(tracerProvider); + setSharedTracer(this.tracer); + } + + protected init(): InstrumentationModuleDefinition[] { + const methodsToInstrument = [...(this.getConfig().customInstrumentation ?? [])]; + if (this.getConfig().requestHandlingInstrumentation) { + methodsToInstrument.push(...requestHandlingInstrumentationMethods); + } + const moduleDefinitions = buildModuleDefinitions(methodsToInstrument); + const definitions = this.instantiateModuleDefinitions(moduleDefinitions); + + if (this.getConfig().logInstrumentation) { + definitions.push( + crawleeModuleDefinition( + '@crawlee/core', + (moduleExports) => { + for (const method of loggerMethods) { + const prototype = this.getPrototype( + moduleExports, + '@crawlee/core', + 'BaseCrawleeLogger', + method.methodName, + ); + if (prototype) { + this._wrap(prototype, method.methodName, this.getLogPatch(method)); + } + } + return moduleExports; + }, + (moduleExports) => { + for (const method of loggerMethods) { + this.unwrapIfWrapped(moduleExports?.BaseCrawleeLogger?.prototype, method.methodName); + } + return moduleExports; + }, + ), + ); + } + return definitions; + } + + private instantiateModuleDefinitions(moduleDefinitions: ModuleDefinition[]): InstrumentationModuleDefinition[] { + return moduleDefinitions.map((definition) => { + return crawleeModuleDefinition( + definition.moduleName, + (moduleExports) => { + for (const patch of definition.classMethodPatches) { + const prototype = this.getPrototype( + moduleExports, + definition.moduleName, + patch.className, + patch.methodName, + ); + if (prototype) { + this._wrap(prototype, patch.methodName, this.applyClassMethodPatch(patch)); + } + } + return moduleExports; + }, + (moduleExports) => { + for (const patch of definition.classMethodPatches) { + this.unwrapIfWrapped(moduleExports?.[patch.className]?.prototype, patch.methodName); + } + return moduleExports; + }, + ); + }); + } + + /** + * Resolves the prototype holding the method to patch, warning instead of throwing when the class or the method + * is not there - a missing internal method must not break loading of the instrumented module. + */ + private getPrototype(moduleExports: any, moduleName: string, className: string, methodName: string) { + const prototype = moduleExports?.[className]?.prototype; + + if (typeof prototype?.[methodName] !== 'function') { + this._diag.warn( + `Skipping instrumentation of ${moduleName}: ${className}.${methodName} was not found. ` + + `The installed version of ${moduleName} is probably not supported by ${PACKAGE_NAME}.`, + ); + return undefined; + } + + return prototype; + } + + /** Mirrors {@link getPrototype}: only methods that were actually patched are restored. */ + private unwrapIfWrapped(prototype: any, methodName: string) { + if (prototype && isWrapped(prototype[methodName])) { + this._unwrap(prototype, methodName); + } + } + + private applyClassMethodPatch(patch: ClassMethodPatchDefinition): (original: any) => any { + const { spanName, spanOptions } = patch; + const qualifiedName = `${patch.className}.${patch.methodName}`; + const codeAttributes = { [ATTR_CODE_FUNCTION_NAME]: qualifiedName }; + + // Both options are resolved through the guarded helpers, so that a throwing callback costs only what the + // caller supplied - the span itself, its name and the attributes added here all survive. + return function wrap(original: (...args: unknown[]) => any) { + return wrapWithSpan(original, { + spanName(this: unknown, ...args: unknown[]): string { + return resolveSpanName(spanName, qualifiedName, this, args); + }, + spanOptions(this: unknown, ...args: unknown[]): SpanOptions { + const resolved = resolveSpanOptions(spanOptions, this, args); + return { ...resolved, attributes: { ...codeAttributes, ...resolved.attributes } }; + }, + }); + }; + } + + private getLogPatch(method: LoggerMethodDefinition) { + // oxlint-disable-next-line no-this-alias + const instrumentation = this; + + return function wrapLog(original: (...args: any[]) => void) { + return function wrappedLog(this: unknown, ...args: any[]): void { + // The application's own logging runs first and its outcome is never affected by the forwarding, + // which matters most where Crawlee logs from inside a `catch` - `handleFailedRequestHandler`. + // These methods are synchronous and return void, so keep them that way. + try { + original.apply(this, args); + } finally { + instrumentation.forwardLogRecord(method, args); + } + }; + }; + } + + /** + * Emits one Crawlee log call as an OpenTelemetry log record. + * + * Everything here - reading the arguments, stringifying the message, handing the record to the SDK - runs inside + * the application's own call to `log.info()` and friends, so a failure anywhere in it is reported and dropped + * rather than raised. + */ + private forwardLogRecord(method: LoggerMethodDefinition, args: unknown[]): void { + try { + const { message, data } = method.read(args); + + // Crawlee leaves level filtering to the logging library, so everything is forwarded and the + // OpenTelemetry pipeline decides what to keep. + this.logger.emit({ + severityNumber: apifyLogLevelMap[method.level] ?? SeverityNumber.UNSPECIFIED, + severityText: apifyLogLevelNameMap[method.level], + body: message, + attributes: buildLogAttributes(data), + }); + } catch (err) { + this._diag.warn(`Failed to forward a Crawlee log record to OpenTelemetry: ${err}`); + } + } +} diff --git a/packages/otel/src/internal-types.ts b/packages/otel/src/internal-types.ts new file mode 100644 index 000000000000..f47d4538c011 --- /dev/null +++ b/packages/otel/src/internal-types.ts @@ -0,0 +1,41 @@ +import type { ClassMethodToInstrument } from './types.js'; + +/** The patches of one instrumented module, as produced by {@link buildModuleDefinitions}. */ +export interface ModuleDefinition { + moduleName: string; + classMethodPatches: ClassMethodPatchDefinition[]; +} + +/** + * A {@link ClassMethodToInstrument} that has already been grouped under its module, so the module name would be + * redundant. Derived from the public type rather than restated, so the fields and their documentation have one home. + */ +export type ClassMethodPatchDefinition = Omit; + +/** + * The fields of a Crawlee `Request` this instrumentation reads. + * + * Deliberately structural rather than imported from `@crawlee/core`: the instrumented Crawlee version is resolved at + * runtime and may not be the one this package was compiled against, so every field is treated as optional. + */ +export interface RequestLike { + id?: string; + url?: string; + method?: string; + retryCount?: number; +} + +/** The part of a Crawlee crawling context this instrumentation reads. */ +export interface CrawlingContextLike { + request?: RequestLike; +} + +/** One of the logging methods `BaseCrawleeLogger` provides, and how to read a log record out of a call to it. */ +export interface LoggerMethodDefinition { + /** The method on `BaseCrawleeLogger.prototype` to patch. */ + methodName: string; + /** The Crawlee log level this method logs at. */ + level: number; + /** Pulls the message and the structured data out of the call arguments, which differ per method. */ + read: (args: unknown[]) => { message: string; data?: Record }; +} diff --git a/packages/otel/src/types.ts b/packages/otel/src/types.ts new file mode 100644 index 000000000000..ec645ebb558e --- /dev/null +++ b/packages/otel/src/types.ts @@ -0,0 +1,27 @@ +import type { SpanOptions } from '@opentelemetry/api'; +import type { InstrumentationConfig } from '@opentelemetry/instrumentation'; + +export interface CrawleeInstrumentationConfig extends InstrumentationConfig { + requestHandlingInstrumentation?: boolean; + logInstrumentation?: boolean; + customInstrumentation?: ClassMethodToInstrument[]; +} + +/** One class method to wrap in a span, and the module that has to be loaded for it to exist. */ +export interface ClassMethodToInstrument { + /** The Crawlee package the class is exported from, for example `@crawlee/basic`. */ + moduleName: string; + /** The class name to patch. */ + className: string; + /** The method name to patch. */ + methodName: string; + /** + * The name of the span. Defaults to `className.methodName`. + * + * When given a function, it is called with the arguments of the patched method, and `this` is the instance the + * method was called on. The arguments are `any` because they are whatever the patched method receives. + */ + spanName?: string | ((this: any, ...args: any[]) => string); + /** The attributes of the span. Follows the same calling convention as {@link ClassMethodToInstrument.spanName}. */ + spanOptions?: SpanOptions | ((this: any, ...args: any[]) => SpanOptions); +} diff --git a/packages/otel/src/utilities.ts b/packages/otel/src/utilities.ts new file mode 100644 index 000000000000..58a9197a7fba --- /dev/null +++ b/packages/otel/src/utilities.ts @@ -0,0 +1,113 @@ +import { readFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; + +import { diag } from '@opentelemetry/api'; +import type { LogAttributes } from '@opentelemetry/api-logs'; +import { + ATTR_EXCEPTION_MESSAGE, + ATTR_EXCEPTION_STACKTRACE, + ATTR_EXCEPTION_TYPE, +} from '@opentelemetry/semantic-conventions'; + +import { PACKAGE_NAME, UNKNOWN_PACKAGE_VERSION } from './constants.js'; +import type { ModuleDefinition } from './internal-types.js'; +import type { ClassMethodToInstrument } from './types.js'; + +interface OtelPackageJson { + version: string; +} + +let packageFile: OtelPackageJson | undefined; + +function getPackageJson(): OtelPackageJson { + if (!packageFile) { + try { + // The package is ESM, so `require` has to be recreated from the module URL. + const packageFilePath = createRequire(import.meta.url).resolve(`${PACKAGE_NAME}/package.json`); + packageFile = JSON.parse(readFileSync(packageFilePath, 'utf8')) as OtelPackageJson; + } catch (err) { + // The version is only reported as the instrumentation scope version, so a failure here must not be fatal. + diag.warn(`Could not determine the ${PACKAGE_NAME} version: ${err}`); + packageFile = { version: UNKNOWN_PACKAGE_VERSION }; + } + } + return packageFile; +} + +export function getPackageVersion(): string { + return getPackageJson().version; +} + +/** + * Turns the structured `data` of a Crawlee log call into OpenTelemetry log attributes. + * + * Crawlee folds a logged error into `data`, so any `Error` value found there is mapped onto the semantic convention + * attributes - its own properties are not enumerable and would otherwise be dropped. + */ +export function buildLogAttributes(data?: unknown): LogAttributes { + const attributes: LogAttributes = {}; + + if (typeof data !== 'object' || data === null || Array.isArray(data)) { + if (data !== undefined) { + attributes['crawlee.log.data'] = String(data); + } + return attributes; + } + + for (const [key, value] of Object.entries(data)) { + if (value instanceof Error) { + attributes[ATTR_EXCEPTION_TYPE] = value.name; + attributes[ATTR_EXCEPTION_MESSAGE] = value.message; + if (value.stack) { + attributes[ATTR_EXCEPTION_STACKTRACE] = value.stack; + } + } else { + attributes[key] = value as LogAttributes[string]; + } + } + + return attributes; +} + +/** + * Groups the methods to instrument by the module that owns them, dropping duplicates. + * + * The first definition of a method wins. `CrawleeInstrumentation` passes `customInstrumentation` ahead of the built-in + * list, so configuring a method that is already instrumented overrides the built-in span rather than being ignored. + */ +export function buildModuleDefinitions(methodsToInstrument: ClassMethodToInstrument[]): ModuleDefinition[] { + const definitions: ModuleDefinition[] = []; + + for (const method of methodsToInstrument) { + let definition = definitions.find((d) => d.moduleName === method.moduleName); + if (!definition) { + if (!method.moduleName.startsWith('@crawlee/')) { + diag.warn(`Module ${method.moduleName} is not a valid Crawlee module. Skipping.`); + continue; + } + definition = { + moduleName: method.moduleName, + classMethodPatches: [], + }; + definitions.push(definition); + } + if ( + !definition.classMethodPatches.find( + (p) => p.className === method.className && p.methodName === method.methodName, + ) + ) { + definition.classMethodPatches.push({ + className: method.className, + methodName: method.methodName, + spanName: method.spanName, + spanOptions: method.spanOptions, + }); + } else { + diag.warn( + `Method ${method.className}.${method.methodName} is instrumented more than once. Keeping the first ` + + `definition, which is the \`customInstrumentation\` entry when one exists for the method.`, + ); + } + } + return definitions; +} diff --git a/packages/otel/src/wrapWithSpan.ts b/packages/otel/src/wrapWithSpan.ts new file mode 100644 index 000000000000..c96f7d932401 --- /dev/null +++ b/packages/otel/src/wrapWithSpan.ts @@ -0,0 +1,148 @@ +import type { Exception, Span, SpanOptions, Tracer } from '@opentelemetry/api'; +import { diag, SpanStatusCode, trace } from '@opentelemetry/api'; + +import { PACKAGE_NAME } from './constants.js'; +import { getPackageVersion } from './utilities.js'; + +/** + * The tracer `CrawleeInstrumentation` hands over once it knows which provider it ended up with, so that manually + * wrapped handlers share the instrumentation scope of the automatic spans. + * + * Module level state, because `wrapWithSpan` is called from user code that holds no reference to the instrumentation. + */ +let sharedTracer: Tracer | undefined; + +/** + * Points the exported {@link wrapWithSpan} at a tracer, or back at the global API when passed `undefined`. + * + * @internal + */ +export function setSharedTracer(tracer: Tracer | undefined): void { + sharedTracer = tracer; +} + +/** + * Wraps a function with OpenTelemetry span instrumentation. + * + * `Args` and `Return` are separate generics so that the argument types flow through to the `spanName` and `spanOptions` + * callbacks. They are inferred from the wrapped function, so annotate its parameters when assigning the result to an + * option whose type is a union - `requestHandler` accepts both a router and a plain handler, and TypeScript cannot + * infer parameter types through a union of function types: + * + * ```ts + * requestHandler: wrapWithSpan(async ({ request }: CheerioCrawlingContext) => { ... }) + * ``` + * + * Synchronous functions stay synchronous, asynchronous ones keep their span open until the returned promise settles. + * + * The wrapper forwards its own `this` to the wrapped function, so a method keeps working when wrapped. An arrow + * function still ignores it, as arrow functions always take `this` from where they were defined. + */ +export function wrapWithSpan( + fn: (...args: Args) => Return, + options?: { + spanName?: string | ((...args: Args) => string); + spanOptions?: SpanOptions | ((...args: Args) => SpanOptions); + tracer?: Tracer; + }, +): (...args: Args) => Return { + return function (this: unknown, ...args: Args): Return { + // Resolving the tracer lazily lets `CrawleeInstrumentation` hand over its tracer at any point. When no + // instrumentation is registered, we fall back to the global API, which returns a tracer that either + // delegates to the globally registered provider or is a no-op - so wrapping never fails on its own. + const tracer = options?.tracer ?? sharedTracer ?? trace.getTracer(PACKAGE_NAME, getPackageVersion()); + const spanName = resolveSpanName(options?.spanName, fn.name || 'anonymous', this, args); + const spanOptions = resolveSpanOptions(options?.spanOptions, this, args); + + return tracer.startActiveSpan(spanName, spanOptions, (span): Return => { + let result: Return; + + try { + result = fn.apply(this, args); + } catch (err) { + recordError(span, err); + span.end(); + throw err; + } + + // Only defer ending the span when the wrapped function is actually asynchronous, so that wrapping + // a synchronous function does not silently turn it into a promise-returning one. + if (!isPromiseLike(result)) { + span.end(); + return result; + } + + return Promise.resolve(result).then( + (value) => { + span.end(); + return value; + }, + (err) => { + recordError(span, err); + span.end(); + throw err; + }, + ) as Return; + }); + }; +} + +/** @internal Shared with `CrawleeInstrumentation`, which supplies a class qualified default. */ +export function resolveSpanName( + spanName: string | ((...args: Args) => string) | undefined, + fallback: string, + thisArg: unknown, + args: Args, +): string { + if (typeof spanName === 'function') { + return callSpanOption(spanName, fallback, thisArg, args, 'spanName'); + } + return spanName ?? fallback; +} + +/** @internal Shared with `CrawleeInstrumentation`, which merges its own attributes into the resolved options. */ +export function resolveSpanOptions( + spanOptions: SpanOptions | ((...args: Args) => SpanOptions) | undefined, + thisArg: unknown, + args: Args, +): SpanOptions { + if (typeof spanOptions === 'function') { + return callSpanOption(spanOptions, {}, thisArg, args, 'spanOptions'); + } + return spanOptions ?? {}; +} + +/** + * Calls a `spanName` or `spanOptions` callback supplied by the caller. + * + * These run inside the call path of the wrapped function, so a mistake in one must not turn into a failure of the + * function being instrumented - the span is created with the default instead. + */ +function callSpanOption( + callback: (...args: Args) => Value, + fallback: Value, + thisArg: unknown, + args: Args, + optionName: string, +): Value { + try { + return callback.apply(thisArg, args); + } catch (err) { + diag.warn(`The ${optionName} callback of a ${PACKAGE_NAME} span threw, using the default instead: ${err}`); + return fallback; + } +} + +function isPromiseLike(value: unknown): value is PromiseLike { + return typeof (value as PromiseLike | undefined)?.then === 'function'; +} + +function recordError(span: Span, err: unknown): void { + span.recordException(err as Exception); + // Per the OpenTelemetry specification, instrumentation only sets the status on failure and leaves successful + // spans `UNSET` - marking them `OK` would prevent consumers from overriding the status themselves. + span.setStatus({ + code: SpanStatusCode.ERROR, + message: err instanceof Error ? err.message : String(err), + }); +} diff --git a/packages/otel/test/constants.test.ts b/packages/otel/test/constants.test.ts new file mode 100644 index 000000000000..ba0ad52297ed --- /dev/null +++ b/packages/otel/test/constants.test.ts @@ -0,0 +1,33 @@ +import { SeverityNumber } from '@opentelemetry/api-logs'; + +import { apifyLogLevelMap, apifyLogLevelNameMap, loggerMethods } from '../src/constants'; + +/** + * The mapping itself is a decision worth pinning down - `SOFT_FAIL` and `WARNING` collapse onto one OpenTelemetry + * severity, and `PERF` has no counterpart at all and is reported as `DEBUG`. + */ +describe('Crawlee log levels', () => { + test.each([ + [1, 'ERROR', SeverityNumber.ERROR], + [2, 'SOFT_FAIL', SeverityNumber.WARN], + [3, 'WARNING', SeverityNumber.WARN], + [4, 'INFO', SeverityNumber.INFO], + [5, 'DEBUG', SeverityNumber.DEBUG], + [6, 'PERF', SeverityNumber.DEBUG], + ])('level %i (%s) is reported as severity %i', (level, name, severity) => { + expect(apifyLogLevelMap[level as number]).toBe(severity); + expect(apifyLogLevelNameMap[level as number]).toBe(name); + }); + + test('OFF has no severity, since nothing is ever logged at it', () => { + expect(apifyLogLevelMap[0]).toBeUndefined(); + expect(apifyLogLevelNameMap[0]).toBeUndefined(); + }); + + test('every instrumented logging method has a level that maps to a severity', () => { + for (const method of loggerMethods) { + expect(apifyLogLevelMap[method.level], `${method.methodName} has no severity`).toBeDefined(); + expect(apifyLogLevelNameMap[method.level], `${method.methodName} has no severity text`).toBeDefined(); + } + }); +}); diff --git a/packages/otel/test/instrumentation.test.ts b/packages/otel/test/instrumentation.test.ts new file mode 100644 index 000000000000..8b21faff2442 --- /dev/null +++ b/packages/otel/test/instrumentation.test.ts @@ -0,0 +1,323 @@ +import { CrawleeInstrumentation } from '@crawlee/otel'; +import { ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from '@opentelemetry/semantic-conventions'; +import { isWrapped } from '@opentelemetry/instrumentation'; +import { satisfies } from 'semver'; + +import { baseConfig, requestHandlingInstrumentationMethods } from '../src/constants'; + +describe('CrawleeInstrumentation', () => { + describe('constructor and configuration', () => { + test('creates instrumentation with default config', () => { + const instrumentation = new CrawleeInstrumentation(); + + expect(instrumentation.instrumentationName).toBe('@crawlee/otel'); + expect(instrumentation.getConfig()).toMatchObject({ + enabled: true, + requestHandlingInstrumentation: true, + logInstrumentation: true, + customInstrumentation: [], + }); + }); + + test('merges provided config with defaults', () => { + const instrumentation = new CrawleeInstrumentation({ + requestHandlingInstrumentation: false, + logInstrumentation: false, + }); + + expect(instrumentation.getConfig()).toMatchObject({ + enabled: true, // default + requestHandlingInstrumentation: false, // overridden + logInstrumentation: false, // overridden + customInstrumentation: [], // default + }); + }); + + test('an explicitly undefined flag keeps its default', () => { + // What `{ logInstrumentation: options.logs }` produces when the caller has no opinion about it. + const instrumentation = new CrawleeInstrumentation({ + enabled: undefined, + requestHandlingInstrumentation: undefined, + logInstrumentation: undefined, + customInstrumentation: undefined, + }); + + expect(instrumentation.getConfig()).toMatchObject({ + enabled: true, + requestHandlingInstrumentation: true, + logInstrumentation: true, + customInstrumentation: [], + }); + }); + + test('accepts custom instrumentation config', () => { + const customMethods = [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'customMethod', + spanName: 'custom.span', + }, + ]; + + const instrumentation = new CrawleeInstrumentation({ + customInstrumentation: customMethods, + }); + + expect(instrumentation.getConfig().customInstrumentation).toEqual(customMethods); + }); + + test('can disable instrumentation entirely', () => { + const instrumentation = new CrawleeInstrumentation({ + enabled: false, + }); + + expect(instrumentation.getConfig().enabled).toBe(false); + }); + }); + + describe('init method', () => { + test('returns module definitions when request handling instrumentation enabled', () => { + const instrumentation = new CrawleeInstrumentation({ + requestHandlingInstrumentation: true, + logInstrumentation: false, + }); + + // Access protected init method for testing + const definitions = (instrumentation as any).init(); + + expect(definitions.length).toBeGreaterThan(0); + }); + + test('returns fewer definitions when request handling disabled', () => { + const withHandling = new CrawleeInstrumentation({ + requestHandlingInstrumentation: true, + logInstrumentation: false, + }); + + const withoutHandling = new CrawleeInstrumentation({ + requestHandlingInstrumentation: false, + logInstrumentation: false, + }); + + const defsWithHandling = (withHandling as any).init(); + const defsWithoutHandling = (withoutHandling as any).init(); + + expect(defsWithHandling.length).toBeGreaterThan(defsWithoutHandling.length); + }); + + test('includes log instrumentation when enabled', () => { + const instrumentation = new CrawleeInstrumentation({ + requestHandlingInstrumentation: false, + logInstrumentation: true, + }); + + const definitions = (instrumentation as any).init(); + + const logDefinition = definitions.find((d: any) => d.name === '@crawlee/core'); + expect(logDefinition).toBeDefined(); + }); + + test('excludes log instrumentation when disabled', () => { + const instrumentation = new CrawleeInstrumentation({ + requestHandlingInstrumentation: false, + logInstrumentation: false, + }); + + const definitions = (instrumentation as any).init(); + + const logDefinition = definitions.find((d: any) => d.name === '@crawlee/core'); + expect(logDefinition).toBeUndefined(); + }); + + test('combines default and custom instrumentation', () => { + const instrumentation = new CrawleeInstrumentation({ + requestHandlingInstrumentation: true, + logInstrumentation: false, + customInstrumentation: [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'customMethod', + spanName: 'custom.span', + }, + ], + }); + + const definition = (instrumentation as any).init().find((d: any) => d.name === '@crawlee/basic') as { + patch: (e: any) => any; + }; + + class BasicCrawler { + run() {} + customMethod() {} + } + definition.patch({ BasicCrawler }); + + // Both the built-in method and the configured one, rather than just a non-empty definition list. + expect(isWrapped(BasicCrawler.prototype.run)).toBe(true); + expect(isWrapped(BasicCrawler.prototype.customMethod)).toBe(true); + }); + }); + + describe('setConfig', () => { + test('allows runtime config changes', () => { + const instrumentation = new CrawleeInstrumentation({ + enabled: true, + }); + + instrumentation.setConfig({ enabled: false }); + + expect(instrumentation.getConfig().enabled).toBe(false); + }); + }); +}); + +describe('baseConfig', () => { + test('has expected default values', () => { + expect(baseConfig).toEqual({ + enabled: true, + requestHandlingInstrumentation: true, + logInstrumentation: true, + customInstrumentation: [], + }); + }); +}); + +describe('requestHandlingInstrumentationMethods', () => { + test('contains expected BasicCrawler methods', () => { + const basicMethods = requestHandlingInstrumentationMethods.filter( + (m: { moduleName: string }) => m.moduleName === '@crawlee/basic', + ); + + expect(basicMethods.length).toBeGreaterThan(0); + + const methodNames = basicMethods.map((m: { methodName: any }) => m.methodName); + expect(methodNames).toContain('run'); + expect(methodNames).toContain('handleRequest'); + expect(methodNames).toContain('runRequestHandler'); + expect(methodNames).toContain('requestFunctionErrorHandler'); + expect(methodNames).toContain('handleFailedRequestHandler'); + }); + + test('contains expected BrowserCrawler methods', () => { + const browserMethods = requestHandlingInstrumentationMethods.filter( + (m: { moduleName: string }) => m.moduleName === '@crawlee/browser', + ); + + expect(browserMethods.length).toBeGreaterThan(0); + + const methodNames = browserMethods.map((m: { methodName: any }) => m.methodName); + expect(methodNames).toContain('navigate'); + }); + + test('contains expected HttpCrawler methods', () => { + const httpMethods = requestHandlingInstrumentationMethods.filter( + (m: { moduleName: string }) => m.moduleName === '@crawlee/http', + ); + + expect(httpMethods.length).toBeGreaterThan(0); + + const methodNames = httpMethods.map((m: { methodName: any }) => m.methodName); + expect(methodNames).toContain('makeHttpRequest'); + }); + + test('all methods have valid moduleName starting with @crawlee/', () => { + for (const method of requestHandlingInstrumentationMethods) { + expect(method.moduleName).toMatch(/^@crawlee\//); + } + }); + + test('all methods have required properties', () => { + for (const method of requestHandlingInstrumentationMethods) { + expect(method.moduleName).toBeDefined(); + expect(method.className).toBeDefined(); + expect(method.methodName).toBeDefined(); + expect(method.spanName).toBeDefined(); + } + }); + + test.each([ + // [methodName, index of the crawling context in the argument list] + ['handleRequest', 0], + ['runRequestHandler', 0], + ['makeHttpRequest', 0], + ['navigate', 0], + ['handleFailedRequestHandler', 0], + // `requestFunctionErrorHandler(error, crawlingContext, request, source)` + ['requestFunctionErrorHandler', 1], + ])('%s reads request attributes from argument %i', (methodName, contextArgIndex) => { + const methods = requestHandlingInstrumentationMethods.filter((m) => m.methodName === methodName); + expect(methods.length).toBeGreaterThan(0); + + const mockContext = { + request: { + id: 'test-id', + url: 'https://example.com', + method: 'GET', + retryCount: 0, + }, + }; + const args = Array.from({ length: contextArgIndex + 1 }); + args[contextArgIndex] = mockContext; + + for (const method of methods) { + expect(typeof method.spanOptions).toBe('function'); + + // oxlint-disable-next-line no-unsafe-function-type + const options = (method.spanOptions as Function)(...args); + expect(options.attributes).toEqual({ + 'crawlee.request.id': 'test-id', + [ATTR_URL_FULL]: 'https://example.com', + [ATTR_HTTP_REQUEST_METHOD]: 'GET', + 'crawlee.request.retry_count': 0, + }); + } + }); + + test('request attributes are empty when the argument is not a crawling context', () => { + const method = requestHandlingInstrumentationMethods.find((m) => m.methodName === 'runRequestHandler')!; + + // oxlint-disable-next-line no-unsafe-function-type + expect((method.spanOptions as Function)(undefined)).toEqual({ attributes: {} }); + }); +}); + +/** + * `@opentelemetry/instrumentation` decides whether to patch a module with + * `semver.satisfies(moduleVersion, supportedVersion, { includePrerelease })` and silently leaves the module alone when + * that is false, so this reads both inputs off the definitions the instrumentation actually produces rather than + * restating the literal. Crawlee v4 is published exclusively under prerelease tags, which a caret range never matches. + */ +describe('supported Crawlee versions', () => { + const definitions = () => (new CrawleeInstrumentation() as any).init() as any[]; + + const isSupported = (definition: any, version: string) => + (definition.supportedVersions as string[]).some((range) => + satisfies(version, range, { includePrerelease: definition.includePrerelease }), + ); + + test('covers every instrumented module', () => { + expect( + definitions() + .map((d) => d.name) + .sort(), + ).toEqual(['@crawlee/basic', '@crawlee/browser', '@crawlee/core', '@crawlee/http', '@crawlee/playwright']); + }); + + // The first two are the versions currently behind the `v4` and `rc` dist-tags. + test.each(['4.0.0-beta.140', '4.0.0-rc.0', '4.0.0', '4.1.0', '4.1.0-beta.3', '4.9.9'])( + 'patches Crawlee %s', + (version) => { + for (const definition of definitions()) { + expect(isSupported(definition, version), `${definition.name} rejected ${version}`).toBe(true); + } + }, + ); + + test.each(['3.13.0', '5.0.0', '5.0.0-beta.0'])('leaves Crawlee %s alone', (version) => { + for (const definition of definitions()) { + expect(isSupported(definition, version), `${definition.name} accepted ${version}`).toBe(false); + } + }); +}); diff --git a/packages/otel/test/patching.test.ts b/packages/otel/test/patching.test.ts new file mode 100644 index 000000000000..eb4a71aea8aa --- /dev/null +++ b/packages/otel/test/patching.test.ts @@ -0,0 +1,416 @@ +import { CrawleeInstrumentation } from '@crawlee/otel'; +import { SeverityNumber } from '@opentelemetry/api-logs'; +import type { LogRecord } from '@opentelemetry/sdk-logs'; +import { InMemoryLogRecordExporter, LoggerProvider, SimpleLogRecordProcessor } from '@opentelemetry/sdk-logs'; +import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'; +import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; +import { + ATTR_CODE_FUNCTION_NAME, + ATTR_EXCEPTION_MESSAGE, + ATTR_EXCEPTION_STACKTRACE, + ATTR_EXCEPTION_TYPE, + ATTR_HTTP_REQUEST_METHOD, + ATTR_URL_FULL, +} from '@opentelemetry/semantic-conventions'; + +/** + * Applies the module patches produced by `init()` to a stub module, which lets us assert what the instrumentation + * actually does to the patched classes without going through the module loader hooks. + */ +function patchModule(instrumentation: CrawleeInstrumentation, moduleName: string, moduleExports: any) { + const definition = (instrumentation as any).init().find((d: any) => d.name === moduleName) as { + patch: (e: any) => any; + unpatch: (e: any) => any; + }; + + expect(definition).toBeDefined(); + definition.patch(moduleExports); + + return definition; +} + +describe('automatic instrumentation', () => { + let provider: NodeTracerProvider; + let exporter: InMemorySpanExporter; + let processor: SimpleSpanProcessor; + + beforeAll(() => { + exporter = new InMemorySpanExporter(); + processor = new SimpleSpanProcessor(exporter); + provider = new NodeTracerProvider({ spanProcessors: [processor] }); + provider.register(); + }); + + beforeEach(() => exporter.reset()); + + afterAll(async () => { + await provider.shutdown(); + }); + + test('wraps the configured method and records request attributes', async () => { + class HttpCrawler { + public seen: string[] = []; + + async makeHttpRequest(crawlingContext: { request: { url: string } }) { + this.seen.push(crawlingContext.request.url); + return 'handled'; + } + } + + const instrumentation = new CrawleeInstrumentation({ logInstrumentation: false }); + patchModule(instrumentation, '@crawlee/http', { HttpCrawler }); + + const crawler = new HttpCrawler(); + const context = { request: { id: 'req-1', url: 'https://example.com', method: 'GET', retryCount: 2 } }; + + await expect(crawler.makeHttpRequest(context)).resolves.toBe('handled'); + // The original behaviour is preserved. + expect(crawler.seen).toEqual(['https://example.com']); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('crawlee.http.makeHttpRequest'); + expect(spans[0].attributes).toEqual({ + 'crawlee.request.id': 'req-1', + [ATTR_URL_FULL]: 'https://example.com', + [ATTR_HTTP_REQUEST_METHOD]: 'GET', + 'crawlee.request.retry_count': 2, + [ATTR_CODE_FUNCTION_NAME]: 'HttpCrawler.makeHttpRequest', + }); + }); + + test('nests the spans of nested instrumented calls', async () => { + class BasicCrawler { + async run() { + return this.handleRequest(); + } + + async handleRequest() { + return 'done'; + } + } + + const instrumentation = new CrawleeInstrumentation({ logInstrumentation: false }); + patchModule(instrumentation, '@crawlee/basic', { BasicCrawler }); + + await new BasicCrawler().run(); + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + const run = spans.find((s: ReadableSpan) => s.name === 'crawlee.crawler.run')!; + const task = spans.find((s: ReadableSpan) => s.name === 'crawlee.crawler.handleRequest')!; + + expect(run).toBeDefined(); + expect(task).toBeDefined(); + expect(task.parentSpanContext?.spanId).toBe(run.spanContext().spanId); + expect(task.spanContext().traceId).toBe(run.spanContext().traceId); + // `run` records the concrete crawler class, resolved through `this`. + expect(run.attributes['crawlee.crawler.type']).toBe('BasicCrawler'); + }); + + test('records the exception and rethrows when the patched method fails', async () => { + class BasicCrawler { + async run(): Promise { + throw new Error('crawl failed'); + } + } + + const instrumentation = new CrawleeInstrumentation({ logInstrumentation: false }); + patchModule(instrumentation, '@crawlee/basic', { BasicCrawler }); + + await expect(new BasicCrawler().run()).rejects.toThrow('crawl failed'); + await processor.forceFlush(); + + const span = exporter.getFinishedSpans().find((s: ReadableSpan) => s.name === 'crawlee.crawler.run')!; + expect(span.status.code).toBe(2); // SpanStatusCode.ERROR + expect(span.events.map((e) => e.name)).toContain('exception'); + }); + + test('unpatch restores the original method', async () => { + class BasicCrawler { + async run() { + return 'ok'; + } + } + + const original = BasicCrawler.prototype.run; + const instrumentation = new CrawleeInstrumentation({ logInstrumentation: false }); + const definition = patchModule(instrumentation, '@crawlee/basic', { BasicCrawler }); + + expect(BasicCrawler.prototype.run).not.toBe(original); + + definition.unpatch({ BasicCrawler }); + + expect(BasicCrawler.prototype.run).toBe(original); + + await new BasicCrawler().run(); + await processor.forceFlush(); + expect(exporter.getFinishedSpans()).toHaveLength(0); + }); + + test('skips a method that does not exist in the installed version instead of throwing', () => { + class BasicCrawler {} + + const instrumentation = new CrawleeInstrumentation({ logInstrumentation: false }); + + // A version of `@crawlee/basic` without the instrumented internals must still load. + expect(() => patchModule(instrumentation, '@crawlee/basic', { BasicCrawler })).not.toThrow(); + }); + + test('skips a class that is not exported by the module instead of throwing', () => { + const instrumentation = new CrawleeInstrumentation({ logInstrumentation: false }); + + expect(() => patchModule(instrumentation, '@crawlee/basic', {})).not.toThrow(); + }); + + test('tolerates an explicitly undefined customInstrumentation', () => { + expect(() => new CrawleeInstrumentation({ customInstrumentation: undefined })).not.toThrow(); + }); +}); + +describe('log instrumentation', () => { + let loggerProvider: LoggerProvider; + let logExporter: InMemoryLogRecordExporter; + + beforeAll(() => { + logExporter = new InMemoryLogRecordExporter(); + loggerProvider = new LoggerProvider({ + processors: [new SimpleLogRecordProcessor(logExporter)], + }); + }); + + beforeEach(() => logExporter.reset()); + + afterAll(async () => { + await loggerProvider.shutdown(); + }); + + /** + * Minimal stand-in for `BaseCrawleeLogger`, mirroring how the real one derives every logging method from the + * abstract `logWithLevel` that each adapter implements. + */ + function createLogModule() { + const calls: unknown[][] = []; + + class BaseCrawleeLogger { + logWithLevel(...args: unknown[]): void { + calls.push(args); + } + + error(message: string, data?: Record) { + this.logWithLevel(1, message, data); + } + + exception(exception: Error, message: string, data?: Record) { + this.logWithLevel(1, `${message}: ${exception.message}`, { ...data, exception }); + } + + warning(message: string, data?: Record) { + this.logWithLevel(3, message, data); + } + + warningOnce(message: string) { + this.warning(message); + } + + info(message: string, data?: Record) { + this.logWithLevel(4, message, data); + } + } + + return { moduleExports: { BaseCrawleeLogger }, calls }; + } + + function patchLog(moduleExports: any) { + const instrumentation = new CrawleeInstrumentation({ requestHandlingInstrumentation: false }); + instrumentation.setLoggerProvider(loggerProvider); + + const definition = (instrumentation as any).init().find((d: any) => d.name === '@crawlee/core') as { + patch: (e: any) => any; + }; + + definition.patch(moduleExports); + } + + test('forwards log records and keeps calling the original method', () => { + const { moduleExports, calls } = createLogModule(); + patchLog(moduleExports); + + new moduleExports.BaseCrawleeLogger().info('hello', { foo: 'bar' }); + + // The original still runs, so the underlying logger keeps printing. + expect(calls).toEqual([[4, 'hello', { foo: 'bar' }]]); + + const records = logExporter.getFinishedLogRecords(); + expect(records).toHaveLength(1); + expect(records[0].body).toBe('hello'); + expect(records[0].severityNumber).toBe(SeverityNumber.INFO); + expect(records[0].severityText).toBe('INFO'); + expect(records[0].attributes).toEqual({ foo: 'bar' }); + }); + + test('returns void, so the original synchronous contract is preserved', () => { + const { moduleExports } = createLogModule(); + patchLog(moduleExports); + + expect(new moduleExports.BaseCrawleeLogger().info('hello')).toBeUndefined(); + }); + + test('forwards a log from any logger implementation, and only once per call', () => { + const { moduleExports } = createLogModule(); + patchLog(moduleExports); + + // A custom adapter only implements `logWithLevel`; the derived methods come from the base class. + class WinstonLikeAdapter extends moduleExports.BaseCrawleeLogger {} + + new WinstonLikeAdapter().warning('from a custom adapter'); + // `warningOnce` routes through `warning`, so it must not emit twice. + new WinstonLikeAdapter().warningOnce('once'); + + const records = logExporter.getFinishedLogRecords(); + expect(records.map((r) => r.body)).toEqual(['from a custom adapter', 'once']); + expect(records.every((r) => r.severityNumber === SeverityNumber.WARN)).toBe(true); + }); + + test('maps an exception onto the semantic convention attributes', () => { + const { moduleExports } = createLogModule(); + patchLog(moduleExports); + + const error = new TypeError('boom'); + new moduleExports.BaseCrawleeLogger().exception(error, 'failed'); + + const record = logExporter.getFinishedLogRecords()[0] as LogRecord; + expect(record.severityNumber).toBe(SeverityNumber.ERROR); + expect(record.attributes[ATTR_EXCEPTION_TYPE]).toBe('TypeError'); + expect(record.attributes[ATTR_EXCEPTION_MESSAGE]).toBe('boom'); + expect(record.attributes[ATTR_EXCEPTION_STACKTRACE]).toContain('TypeError: boom'); + }); +}); + +/** + * An instrumentation must not be able to change the behaviour of the code it patches. Everything the instrumentation + * itself does - reading the log arguments, emitting the record, resolving a user supplied span name or attributes - + * runs inside the application's call path, so a failure in any of it has to stay contained. + */ +describe('telemetry failures are contained', () => { + let provider: NodeTracerProvider; + let exporter: InMemorySpanExporter; + let processor: SimpleSpanProcessor; + + beforeAll(() => { + exporter = new InMemorySpanExporter(); + processor = new SimpleSpanProcessor(exporter); + provider = new NodeTracerProvider({ spanProcessors: [processor] }); + }); + + beforeEach(() => exporter.reset()); + + afterAll(async () => { + await provider.shutdown(); + }); + + /** A logger provider whose records never make it out, standing in for a throwing log record processor. */ + const explodingLoggerProvider = { + getLogger: () => ({ + emit: () => { + throw new Error('log record processor exploded'); + }, + }), + } as unknown as LoggerProvider; + + function patchLogger(loggerProvider: LoggerProvider) { + const calls: unknown[][] = []; + + class BaseCrawleeLogger { + logWithLevel(...args: unknown[]): void { + calls.push(args); + } + + info(message: unknown, data?: Record) { + this.logWithLevel(4, message, data); + } + } + + const instrumentation = new CrawleeInstrumentation({ requestHandlingInstrumentation: false }); + instrumentation.setLoggerProvider(loggerProvider); + const definition = (instrumentation as any).init().find((d: any) => d.name === '@crawlee/core') as { + patch: (e: any) => any; + }; + definition.patch({ BaseCrawleeLogger }); + + return { logger: new BaseCrawleeLogger(), calls }; + } + + test('a throwing log pipeline does not swallow the application log call', () => { + const { logger, calls } = patchLogger(explodingLoggerProvider); + + expect(() => logger.info('hello', { foo: 'bar' })).not.toThrow(); + expect(calls).toEqual([[4, 'hello', { foo: 'bar' }]]); + }); + + test('a message that cannot be stringified does not swallow the application log call', () => { + const { logger, calls } = patchLogger( + new LoggerProvider({ processors: [new SimpleLogRecordProcessor(new InMemoryLogRecordExporter())] }), + ); + const hostile = { + toString() { + throw new Error('nope'); + }, + }; + + expect(() => logger.info(hostile)).not.toThrow(); + expect(calls).toEqual([[4, hostile, undefined]]); + }); + + function patchWithFailingHook(hook: 'spanName' | 'spanOptions') { + class BasicCrawler { + async handleRequest() { + return 'done'; + } + } + + const instrumentation = new CrawleeInstrumentation({ + requestHandlingInstrumentation: false, + logInstrumentation: false, + customInstrumentation: [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'handleRequest', + spanName: 'crawlee.crawler.handleRequest', + [hook]: () => { + throw new Error(`${hook} exploded`); + }, + }, + ], + }); + instrumentation.setTracerProvider(provider); + const definition = (instrumentation as any).init().find((d: any) => d.name === '@crawlee/basic') as { + patch: (e: any) => any; + }; + definition.patch({ BasicCrawler }); + + return new BasicCrawler(); + } + + test('a throwing spanName callback does not break the patched method', async () => { + await expect(patchWithFailingHook('spanName').handleRequest()).resolves.toBe('done'); + + await processor.forceFlush(); + // The span is still recorded, under the method's default name. + expect(exporter.getFinishedSpans().map((s: ReadableSpan) => s.name)).toEqual(['BasicCrawler.handleRequest']); + }); + + test('a throwing spanOptions callback does not break the patched method', async () => { + await expect(patchWithFailingHook('spanOptions').handleRequest()).resolves.toBe('done'); + + await processor.forceFlush(); + const spans = exporter.getFinishedSpans(); + expect(spans.map((s: ReadableSpan) => s.name)).toEqual(['crawlee.crawler.handleRequest']); + // The attributes the instrumentation itself adds are unaffected by the failing callback. + expect(spans[0].attributes).toEqual({ [ATTR_CODE_FUNCTION_NAME]: 'BasicCrawler.handleRequest' }); + }); +}); diff --git a/packages/otel/test/tsconfig.json b/packages/otel/test/tsconfig.json new file mode 100644 index 000000000000..eb8cbab58123 --- /dev/null +++ b/packages/otel/test/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.json", + "include": ["**/*", "../../**/*"], + "compilerOptions": { + "types": ["vitest/globals"] + } +} diff --git a/packages/otel/test/utilities.test.ts b/packages/otel/test/utilities.test.ts new file mode 100644 index 000000000000..5a4bf8383310 --- /dev/null +++ b/packages/otel/test/utilities.test.ts @@ -0,0 +1,221 @@ +import type { ClassMethodToInstrument } from '@crawlee/otel'; +import { diag } from '@opentelemetry/api'; + +import { buildModuleDefinitions } from '../src/utilities'; + +describe('buildModuleDefinitions', () => { + let diagWarnSpy: ReturnType; + + beforeEach(() => { + diagWarnSpy = vi.spyOn(diag, 'warn').mockImplementation(() => {}); + }); + + afterEach(() => { + diagWarnSpy.mockRestore(); + }); + + test('builds module definitions from method list', () => { + const methods: ClassMethodToInstrument[] = [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'crawlee.crawler.run', + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: '_runTaskFunction', + spanName: 'crawlee.crawler.runTaskFunction', + }, + ]; + + const definitions = buildModuleDefinitions(methods); + + expect(definitions).toHaveLength(1); + expect(definitions[0].moduleName).toBe('@crawlee/basic'); + expect(definitions[0].classMethodPatches).toHaveLength(2); + expect(definitions[0].classMethodPatches[0]).toEqual({ + className: 'BasicCrawler', + methodName: 'run', + spanName: 'crawlee.crawler.run', + spanOptions: undefined, + }); + expect(definitions[0].classMethodPatches[1]).toEqual({ + className: 'BasicCrawler', + methodName: '_runTaskFunction', + spanName: 'crawlee.crawler.runTaskFunction', + spanOptions: undefined, + }); + }); + + test('groups methods by module name', () => { + const methods: ClassMethodToInstrument[] = [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'basic.run', + }, + { + moduleName: '@crawlee/browser', + className: 'BrowserCrawler', + methodName: '_handleNavigation', + spanName: 'browser.navigation', + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: '_executeHooks', + spanName: 'basic.hooks', + }, + ]; + + const definitions = buildModuleDefinitions(methods); + + expect(definitions).toHaveLength(2); + + const basicDef = definitions.find((d) => d.moduleName === '@crawlee/basic'); + const browserDef = definitions.find((d) => d.moduleName === '@crawlee/browser'); + + expect(basicDef?.classMethodPatches).toHaveLength(2); + expect(browserDef?.classMethodPatches).toHaveLength(1); + }); + + test('skips non-crawlee modules and logs warning', () => { + const methods: ClassMethodToInstrument[] = [ + { + moduleName: 'some-other-package', + className: 'SomeClass', + methodName: 'someMethod', + spanName: 'some-span', + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'basic.run', + }, + ]; + + const definitions = buildModuleDefinitions(methods); + + expect(definitions).toHaveLength(1); + expect(definitions[0].moduleName).toBe('@crawlee/basic'); + expect(diagWarnSpy).toHaveBeenCalledWith('Module some-other-package is not a valid Crawlee module. Skipping.'); + }); + + test('skips duplicate method instrumentation and logs warning', () => { + const methods: ClassMethodToInstrument[] = [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'first-span', + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'duplicate-span', + }, + ]; + + const definitions = buildModuleDefinitions(methods); + + expect(definitions).toHaveLength(1); + expect(definitions[0].classMethodPatches).toHaveLength(1); + expect(definitions[0].classMethodPatches[0].spanName).toBe('first-span'); + expect(diagWarnSpy).toHaveBeenCalledWith(expect.stringContaining('Keeping the first definition')); + }); + + test('allows same method name on different classes', () => { + const methods: ClassMethodToInstrument[] = [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'basic.run', + }, + { + moduleName: '@crawlee/basic', + className: 'AnotherCrawler', + methodName: 'run', + spanName: 'another.run', + }, + ]; + + const definitions = buildModuleDefinitions(methods); + + expect(definitions).toHaveLength(1); + expect(definitions[0].classMethodPatches).toHaveLength(2); + }); + + test('preserves spanOptions function', () => { + const spanOptionsFn = (ctx: any) => ({ + attributes: { 'test.attr': ctx.value }, + }); + + const methods: ClassMethodToInstrument[] = [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + spanName: 'span-with-options', + spanOptions: spanOptionsFn, + }, + ]; + + const definitions = buildModuleDefinitions(methods); + + expect(definitions[0].classMethodPatches[0].spanOptions).toBe(spanOptionsFn); + }); + + test('returns empty array for empty input', () => { + const definitions = buildModuleDefinitions([]); + + expect(definitions).toEqual([]); + }); + + test('handles multiple modules with multiple classes', () => { + const methods: ClassMethodToInstrument[] = [ + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'run', + }, + { + moduleName: '@crawlee/basic', + className: 'BasicCrawler', + methodName: 'stop', + }, + { + moduleName: '@crawlee/browser', + className: 'BrowserCrawler', + methodName: 'run', + }, + { + moduleName: '@crawlee/browser', + className: 'BrowserCrawler', + methodName: '_handleNavigation', + }, + { + moduleName: '@crawlee/http', + className: 'HttpCrawler', + methodName: 'run', + }, + ]; + + const definitions = buildModuleDefinitions(methods); + + expect(definitions).toHaveLength(3); + + const basicDef = definitions.find((d) => d.moduleName === '@crawlee/basic'); + const browserDef = definitions.find((d) => d.moduleName === '@crawlee/browser'); + const httpDef = definitions.find((d) => d.moduleName === '@crawlee/http'); + + expect(basicDef?.classMethodPatches).toHaveLength(2); + expect(browserDef?.classMethodPatches).toHaveLength(2); + expect(httpDef?.classMethodPatches).toHaveLength(1); + }); +}); diff --git a/packages/otel/test/wrap-with-span.test.ts b/packages/otel/test/wrap-with-span.test.ts new file mode 100644 index 000000000000..8d8ba906609d --- /dev/null +++ b/packages/otel/test/wrap-with-span.test.ts @@ -0,0 +1,444 @@ +import { SpanStatusCode, trace } from '@opentelemetry/api'; +import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'; +import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; + +import { setSharedTracer, wrapWithSpan } from '../src/wrapWithSpan'; + +describe('wrapWithSpan', () => { + let provider: NodeTracerProvider; + let exporter: InMemorySpanExporter; + let processor: SimpleSpanProcessor; + + beforeAll(() => { + exporter = new InMemorySpanExporter(); + processor = new SimpleSpanProcessor(exporter); + provider = new NodeTracerProvider({ + spanProcessors: [processor], + }); + provider.register(); + }); + + beforeEach(() => { + exporter.reset(); + }); + + afterAll(async () => { + await provider.shutdown(); + }); + + describe('basic functionality', () => { + test('wraps a sync function and creates a span', async () => { + const fn = vi.fn(() => 'result'); + const wrapped = wrapWithSpan(fn, { + spanName: 'test-span', + tracer: provider.getTracer('test-tracer'), + }); + + const result = await wrapped(); + + await processor.forceFlush(); + + expect(result).toBe('result'); + expect(fn).toHaveBeenCalledOnce(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('test-span'); + // Instrumentation leaves successful spans UNSET so consumers can set their own status. + expect(spans[0].status.code).toBe(SpanStatusCode.UNSET); + }); + + test('wraps an async function and creates a span', async () => { + const fn = vi.fn(async () => { + await new Promise((resolve) => setTimeout(resolve, 10)); + return 'async-result'; + }); + const wrapped = wrapWithSpan(fn, { + spanName: 'async-span', + tracer: provider.getTracer('test-tracer'), + }); + + const result = await wrapped(); + + await processor.forceFlush(); + + expect(result).toBe('async-result'); + expect(fn).toHaveBeenCalledOnce(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('async-span'); + expect(spans[0].status.code).toBe(SpanStatusCode.UNSET); + }); + + test('keeps a sync function synchronous', async () => { + const fn = vi.fn(() => 'sync-result'); + const wrapped = wrapWithSpan(fn, { + spanName: 'sync-span', + tracer: provider.getTracer('test-tracer'), + }); + + const result = wrapped(); + + expect(result).toBe('sync-result'); + expect(result).not.toBeInstanceOf(Promise); + + // The span of a sync function is closed before the call returns. + await processor.forceFlush(); + expect(exporter.getFinishedSpans()).toHaveLength(1); + }); + + test('passes arguments to the wrapped function', async () => { + const fn = vi.fn((a: number, b: string) => `${a}-${b}`); + const wrapped = wrapWithSpan(fn, { + spanName: 'args-span', + tracer: provider.getTracer('test-tracer'), + }); + + const result = await wrapped(42, 'hello'); + + expect(result).toBe('42-hello'); + expect(fn).toHaveBeenCalledWith(42, 'hello'); + }); + + test('uses function name as span name when no spanName provided', async () => { + function namedFunction() { + return 'named'; + } + const wrapped = wrapWithSpan(namedFunction, { + tracer: provider.getTracer('test-tracer'), + }); + + wrapped(); + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('namedFunction'); + }); + + test('uses "anonymous" as span name for anonymous functions without spanName', async () => { + const wrapped = wrapWithSpan(() => 'anon', { + tracer: provider.getTracer('test-tracer'), + }); + + wrapped(); + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('anonymous'); + }); + }); + + describe('error handling', () => { + test('records exception and sets error status when function throws', async () => { + const error = new Error('Test error'); + const fn = vi.fn(() => { + throw error; + }); + const wrapped = wrapWithSpan(fn, { + spanName: 'error-span', + tracer: provider.getTracer('test-tracer'), + }); + + // A sync function throws synchronously - it is not turned into a rejected promise. + expect(() => wrapped()).toThrow('Test error'); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('error-span'); + expect(spans[0].status.code).toBe(SpanStatusCode.ERROR); + expect(spans[0].events).toHaveLength(1); + expect(spans[0].events[0].name).toBe('exception'); + }); + + test('records exception for async function rejection', async () => { + const fn = vi.fn(async () => { + await new Promise((resolve) => setTimeout(resolve, 5)); + throw new Error('Async error'); + }); + const wrapped = wrapWithSpan(fn, { + spanName: 'async-error-span', + tracer: provider.getTracer('test-tracer'), + }); + + await expect(wrapped()).rejects.toThrow('Async error'); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].status.code).toBe(SpanStatusCode.ERROR); + }); + }); + + describe('dynamic span name', () => { + test('supports function-based spanName', async () => { + const fn = vi.fn((url: string) => `fetched: ${url}`); + const wrapped = wrapWithSpan(fn, { + spanName: (url: string) => `fetch ${url}`, + tracer: provider.getTracer('test-tracer'), + }); + + await wrapped('https://example.com'); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('fetch https://example.com'); + }); + + test('spanName function receives all arguments', async () => { + const fn = vi.fn((a: number, b: number) => a + b); + const wrapped = wrapWithSpan(fn, { + spanName: (a: number, b: number) => `add-${a}-${b}`, + tracer: provider.getTracer('test-tracer'), + }); + + await wrapped(1, 2); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('add-1-2'); + }); + }); + + describe('span options and attributes', () => { + test('supports static spanOptions', async () => { + const fn = vi.fn(() => 'result'); + const wrapped = wrapWithSpan(fn, { + spanName: 'with-attrs', + spanOptions: { + attributes: { + 'custom.attr': 'value', + 'custom.number': 42, + }, + }, + tracer: provider.getTracer('test-tracer'), + }); + + await wrapped(); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].attributes['custom.attr']).toBe('value'); + expect(spans[0].attributes['custom.number']).toBe(42); + }); + + test('supports function-based spanOptions', async () => { + interface Request { + url: string; + method: string; + } + + const fn = vi.fn((req: Request) => `handled ${req.url}`); + const wrapped = wrapWithSpan(fn, { + spanName: 'dynamic-attrs', + spanOptions: (req: Request) => ({ + attributes: { + 'request.url': req.url, + 'request.method': req.method, + }, + }), + tracer: provider.getTracer('test-tracer'), + }); + + await wrapped({ url: 'https://example.com', method: 'GET' }); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].attributes['request.url']).toBe('https://example.com'); + expect(spans[0].attributes['request.method']).toBe('GET'); + }); + }); + + describe('context propagation', () => { + test('multiple wrapped calls create separate spans', async () => { + const fn1 = vi.fn(() => 'result1'); + const fn2 = vi.fn(() => 'result2'); + const wrapped1 = wrapWithSpan(fn1, { + spanName: 'span-1', + tracer: provider.getTracer('test-tracer'), + }); + const wrapped2 = wrapWithSpan(fn2, { + spanName: 'span-2', + tracer: provider.getTracer('test-tracer'), + }); + + await wrapped1(); + await wrapped2(); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(2); + expect(spans.map((s) => s.name).sort()).toEqual(['span-1', 'span-2']); + }); + + test('concurrent wrapped calls each create their own span', async () => { + const fn = vi.fn(async (id: number) => { + await new Promise((resolve) => setTimeout(resolve, 5)); + return `result-${id}`; + }); + + const wrapped = wrapWithSpan(fn, { + spanName: (id: number) => `concurrent-span-${id}`, + tracer: provider.getTracer('test-tracer'), + }); + + await Promise.all([wrapped(1), wrapped(2), wrapped(3)]); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(3); + expect(spans.map((s) => s.name).sort()).toEqual([ + 'concurrent-span-1', + 'concurrent-span-2', + 'concurrent-span-3', + ]); + }); + + test('nested wrapWithSpan creates multiple spans', async () => { + const innerFn = vi.fn(() => 'inner'); + const wrappedInner = wrapWithSpan(innerFn, { + spanName: 'inner-span', + tracer: provider.getTracer('test-tracer'), + }); + + const outerFn = vi.fn(async () => { + return wrappedInner(); + }); + const wrappedOuter = wrapWithSpan(outerFn, { + spanName: 'outer-span', + tracer: provider.getTracer('test-tracer'), + }); + + await wrappedOuter(); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(2); + + const innerSpan = spans.find((s: ReadableSpan) => s.name === 'inner-span'); + const outerSpan = spans.find((s: ReadableSpan) => s.name === 'outer-span'); + + expect(innerSpan).toBeDefined(); + expect(outerSpan).toBeDefined(); + }); + }); + + describe('custom tracer', () => { + test('uses custom tracer when provided', async () => { + const customTracer = trace.getTracer('custom-tracer', '1.0.0'); + const fn = vi.fn(() => 'result'); + const wrapped = wrapWithSpan(fn, { + spanName: 'custom-tracer-span', + tracer: customTracer, + }); + + await wrapped(); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + // Use instrumentationScope (newer SDK) or instrumentationLibrary (older SDK) + const span = spans[0] as any; + const scope = span.instrumentationScope ?? span.instrumentationLibrary; + expect(scope.name).toBe('custom-tracer'); + expect(scope.version).toBe('1.0.0'); + }); + + test('uses the tracer handed over by the instrumentation', async () => { + const fn = vi.fn(() => 'result'); + const tracer = trace.getTracer('crawlee'); + setSharedTracer(tracer); + const wrapped = wrapWithSpan(fn); + + await wrapped(); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + // Use instrumentationScope (newer SDK) or instrumentationLibrary (older SDK) + const span = spans[0] as any; + const scope = span.instrumentationScope ?? span.instrumentationLibrary; + expect(scope.name).toBe('crawlee'); + }); + + test('falls back to the global tracer provider when no tracer was set', async () => { + // Nothing has handed a tracer over - wrapping must still work instead of throwing. + setSharedTracer(undefined); + + const wrapped = wrapWithSpan(() => 'result', { spanName: 'fallback-span' }); + + expect(wrapped()).toBe('result'); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('fallback-span'); + const scope = (spans[0] as any).instrumentationScope ?? (spans[0] as any).instrumentationLibrary; + expect(scope.name).toBe('@crawlee/otel'); + }); + }); + + describe('this context', () => { + beforeEach(() => { + // Do not depend on a tracer set by an earlier test. + setSharedTracer(provider.getTracer('test-tracer')); + }); + + test('preserves this context for regular functions', () => { + const obj = { + value: 42, + getValue() { + return this.value; + }, + }; + + const wrapped = wrapWithSpan(obj.getValue, { spanName: 'this-span' }); + const result = wrapped.call(obj); + + expect(result).toBe(42); + }); + + test('spanName function receives this context', async () => { + const obj = { + name: 'TestObject', + doSomething() { + return 'done'; + }, + }; + + const wrapped = wrapWithSpan(obj.doSomething, { + spanName(this: typeof obj) { + return `span-for-${this.name}`; + }, + }); + + wrapped.call(obj); + + await processor.forceFlush(); + + const spans = exporter.getFinishedSpans(); + expect(spans).toHaveLength(1); + expect(spans[0].name).toBe('span-for-TestObject'); + }); + }); +}); diff --git a/packages/otel/tsconfig.build.json b/packages/otel/tsconfig.build.json new file mode 100644 index 000000000000..5f63b6d3df40 --- /dev/null +++ b/packages/otel/tsconfig.build.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.build.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/packages/otel/tsconfig.json b/packages/otel/tsconfig.json new file mode 100644 index 000000000000..66bb87a91ee7 --- /dev/null +++ b/packages/otel/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8bdcd9e027b0..540b3d434725 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -266,6 +266,9 @@ importers: '@crawlee/linkedom': specifier: workspace:* version: link:packages/linkedom-crawler + '@crawlee/otel': + specifier: workspace:* + version: link:packages/otel '@crawlee/playwright': specifier: workspace:* version: link:packages/playwright-crawler @@ -281,6 +284,30 @@ importers: '@crawlee/utils': specifier: workspace:* version: link:packages/utils + '@microsoft/api-extractor': + specifier: ^7.58.9 + version: 7.59.0(@types/node@24.12.2) + '@opentelemetry/api': + specifier: ^1.9.0 + version: 1.9.0 + '@opentelemetry/api-logs': + specifier: ^0.210.0 + version: 0.210.0 + '@opentelemetry/instrumentation': + specifier: ^0.210.0 + version: 0.210.0(@opentelemetry/api@1.9.0)(supports-color@7.2.0) + '@opentelemetry/sdk-logs': + specifier: ^0.210.0 + version: 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': + specifier: ^2.0.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': + specifier: ^2.0.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': + specifier: ^1.39.0 + version: 1.43.0 '@oxlint/plugins': specifier: ^1.62.0 version: 1.62.0 @@ -476,9 +503,30 @@ importers: '@crawlee/impit-client': specifier: workspace:* version: link:../packages/impit-client + '@crawlee/otel': + specifier: workspace:* + version: link:../packages/otel '@crawlee/stagehand': specifier: workspace:* version: link:../packages/stagehand-crawler + '@opentelemetry/api': + specifier: ^1.9.0 + version: 1.9.0 + '@opentelemetry/exporter-trace-otlp-grpc': + specifier: ^0.210.0 + version: 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': + specifier: ^2.0.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-node': + specifier: ^0.210.0 + version: 0.210.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1) + '@opentelemetry/sdk-trace-base': + specifier: ^2.0.0 + version: 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': + specifier: ^1.39.0 + version: 1.43.0 apify: specifier: ^4.0.0-beta.24 version: 4.0.0-beta.24(bufferutil@4.1.0)(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1) @@ -962,6 +1010,25 @@ importers: specifier: ^2.8.1 version: 2.8.1 + packages/otel: + dependencies: + '@opentelemetry/instrumentation': + specifier: ^0.210.0 + version: 0.210.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1) + '@opentelemetry/semantic-conventions': + specifier: ^1.39.0 + version: 1.43.0 + devDependencies: + '@opentelemetry/api': + specifier: ^1.9.0 + version: 1.9.0 + '@opentelemetry/api-logs': + specifier: ^0.210.0 + version: 0.210.0 + semver: + specifier: ^7.7.0 + version: 7.7.4 + packages/playwright-crawler: dependencies: '@apify/datastructures': @@ -1087,7 +1154,7 @@ importers: devDependencies: '@browserbasehq/stagehand': specifier: 3.0.7 - version: 3.0.7(@cfworker/json-schema@4.1.1)(@opentelemetry/api@1.9.0)(deepmerge@4.3.1)(dotenv@16.4.7)(encoding@0.1.13)(supports-color@8.1.1)(zod@4.4.3) + version: 3.0.7(@cfworker/json-schema@4.1.1)(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(deepmerge@4.3.1)(dotenv@16.4.7)(encoding@0.1.13)(supports-color@8.1.1)(zod@4.4.3) playwright: specifier: ^1.60.0 version: 1.61.1 @@ -3091,6 +3158,15 @@ packages: '@modelcontextprotocol/sdk': optional: true + '@grpc/grpc-js@1.14.4': + resolution: {integrity: sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==} + engines: {node: '>=12.10.0'} + + '@grpc/proto-loader@0.8.1': + resolution: {integrity: sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==} + engines: {node: '>=6'} + hasBin: true + '@hapi/hoek@9.3.0': resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} @@ -3314,6 +3390,9 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@js-sdsl/ordered-map@4.4.2': + resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + '@jsonjoy.com/base64@1.1.2': resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} engines: {node: '>=10.0'} @@ -3468,6 +3547,21 @@ packages: '@mermaid-js/parser@1.2.0': resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} + '@microsoft/api-extractor-model@7.33.11': + resolution: {integrity: sha512-iDu1AtuRC2Z8XVs2SieZieVavF1FXPBX1C9pMexJh8Dx/Dd/3ZZ4nRQp/PU2Vk2rUHWuBz1wOyL4DcuhVnBXwg==} + engines: {node: '>=20.9.0'} + + '@microsoft/api-extractor@7.59.0': + resolution: {integrity: sha512-KDYV8kSVjmG8JJWVg1f1aKxteNG1IQ44D07Rjhlcci8wlqrSFNhUfgv7dJhwT0W2h3NDIL5Vz2f+/DfO4OpDHw==} + engines: {node: '>=20.9.0'} + hasBin: true + + '@microsoft/tsdoc-config@0.18.1': + resolution: {integrity: sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==} + + '@microsoft/tsdoc@0.16.0': + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + '@modelcontextprotocol/sdk@1.29.0': resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} engines: {node: '>=18'} @@ -3746,10 +3840,210 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@opentelemetry/api-logs@0.210.0': + resolution: {integrity: sha512-CMtLxp+lYDriveZejpBND/2TmadrrhUfChyxzmkFtHaMDdSKfP59MAYyA0ICBvEBdm3iXwLcaj/8Ic/pnGw9Yg==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} + '@opentelemetry/configuration@0.210.0': + resolution: {integrity: sha512-tM0ROS/hZM72kB55cSjDcghVcUXBJdGkGzpkhD7M1B/gpcvZPSGfjFgKN3dgmxNgF76NxtbUwv3ik0wS+Kz52g==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + + '@opentelemetry/context-async-hooks@2.10.0': + resolution: {integrity: sha512-bvyMcgLEkozzSzpEEEo1OMoeQ97bxj6Qs2uN3mPrSdDvObMI1myffD/BPqcLlzZO9//d1SqQA/WPw7Cz2AiqhA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/context-async-hooks@2.4.0': + resolution: {integrity: sha512-jn0phJ+hU7ZuvaoZE/8/Euw3gvHJrn2yi+kXrymwObEPVPjtwCmkvXDRQCWli+fCTTF/aSOtXaLr7CLIvv3LQg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.10.0': + resolution: {integrity: sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.4.0': + resolution: {integrity: sha512-KtcyFHssTn5ZgDu6SXmUznS80OFs/wN7y6MyFRRcKU6TOw8hNcGxKvt8hsdaLJfhzUszNSjURetq5Qpkad14Gw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/exporter-logs-otlp-grpc@0.210.0': + resolution: {integrity: sha512-+BolenqOO6ow65go7uWRYPvvs/BBIWp1mtRn93VvGduqvMVH/IY8nXrt80a4L9hZ7lHi2Tq2/NcC3H2QzcWKag==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-logs-otlp-http@0.210.0': + resolution: {integrity: sha512-Q8/SEQtgrErbVVRg9M9iaG8m5wdPNdU0UOF7U43sAhwfmPG92ZOk/aenKhg0DXSNJHhkCDNCgS1kSoErAB3z0A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-logs-otlp-proto@0.210.0': + resolution: {integrity: sha512-Y/yPc+gDhsWB7AsNzQWxblw4ULbvhCycMaQ2aAn+HSAVbgbMiZa0SbclPVHSnpnNzKSLVavFjweAr0pQA1KKLg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-metrics-otlp-grpc@0.210.0': + resolution: {integrity: sha512-pWZ/Tjrqev9rdkqe8F6A9FGddLZrjl6iRAU5LBvvRL6I3PSgG8z1xM0cESAy1jzAF4wGohnAh8rB7hHzpUOYEA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-metrics-otlp-http@0.210.0': + resolution: {integrity: sha512-JpLThG8Hh8A/Jzdzw9i4Ftu+EzvLaX/LouN+mOOHmadL0iror0Qsi3QWzucXeiUsDDsiYgjfKyi09e6sltytgA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-metrics-otlp-proto@0.210.0': + resolution: {integrity: sha512-CFa7SOinYOVWIWJuQL7XFeyedzmFGIpHpSMNFE8Xefb6iGB4m+MukQecdssvPcJKYlfF5FpovEOLXwafAzsXWQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-prometheus@0.210.0': + resolution: {integrity: sha512-8i+7d70Hho6pcheTtbqIuS+bo+AIX/oNUTMwIEZoehUE4ZdbGmeVaE+hJS2LAErFeFaU71w164lAgYyMUEQ8zw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-trace-otlp-grpc@0.210.0': + resolution: {integrity: sha512-1GPLOyxIfUX24WM8Oea+vx9d9TlewposUnsQXTjusxVMQ/dWvt5JIDJyTsfNDS412XRUOORgF97PwsfDY5QKGA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-trace-otlp-http@0.210.0': + resolution: {integrity: sha512-9JkyaCl70anEtuKZdoCQmjDuz1/paEixY/DWfsvHt7PGKq3t8/nQ/6/xwxHjG+SkPAUbo1Iq4h7STe7Pk2bc5A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-trace-otlp-proto@0.210.0': + resolution: {integrity: sha512-qVUY7Hsm/t5buGOtPcTV1Ch4W9kj2wGaQaAF5FO4XR8TMKl2GM45tUCnr0/1dF3wo4RG9khMxrddeQWdRL4fIg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-zipkin@2.4.0': + resolution: {integrity: sha512-qpiXY0TUEFjBBp9b1na9LfuVQw6W8LH+te7uv+CC+0Up78ZDtZZwOjK2M7CL7Nspnw+yS4JdgEA7oxsBu0Ctsg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + + '@opentelemetry/instrumentation@0.210.0': + resolution: {integrity: sha512-sLMhyHmW9katVaLUOKpfCnxSGhZq2t1ReWgwsu2cSgxmDVMB690H9TanuexanpFI94PJaokrqbp8u9KYZDUT5g==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-exporter-base@0.210.0': + resolution: {integrity: sha512-uk78DcZoBNHIm26h0oXc8Pizh4KDJ/y04N5k/UaI9J7xR7mL8QcMcYPQG9xxN7m8qotXOMDRW6qTAyptav4+3w==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-grpc-exporter-base@0.210.0': + resolution: {integrity: sha512-fEJs8UhkFMrdXMOCLXyKd2uc6N209tIi8IBNqSTi83ri+MlMFrBKnOtklmv9/zzxovoN5zD1waRt6XBFGPfmIw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-transformer@0.210.0': + resolution: {integrity: sha512-nkHBJVSJGOwkRZl+BFIr7gikA93/U8XkL2EWaiDbj3DVjmTEZQpegIKk0lT8oqQYfP8FC6zWNjuTfkaBVqa0ZQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/propagator-b3@2.4.0': + resolution: {integrity: sha512-6VPsFiMUkJBre/86F0d+PZMaUCcuLA9DtZuC46KH8EeVEKZPEM2WlX35M/qmde8UpzoQL9qzdz54YjUYABt8Uw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/propagator-jaeger@2.4.0': + resolution: {integrity: sha512-t6muBL/3AMD++1EMF658C/KIpj3gfmTmftX3mEQql4KIxNGFvacCmmTtrQt9IZAJmQRfjQRCkv+vsGbQugeJIw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/resources@2.10.0': + resolution: {integrity: sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/resources@2.4.0': + resolution: {integrity: sha512-RWvGLj2lMDZd7M/5tjkI/2VHMpXebLgPKvBUd9LRasEWR2xAynDwEYZuLvY9P2NGG73HF07jbbgWX2C9oavcQg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-logs@0.210.0': + resolution: {integrity: sha512-YuaL92Dpyk/Kc1o4e9XiaWWwiC0aBFN+4oy+6A9TP4UNJmRymPMEX10r6EMMFMD7V0hktiSig9cwWo59peeLCQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.10.0' + + '@opentelemetry/sdk-metrics@2.4.0': + resolution: {integrity: sha512-qSbfq9mXbLMqmPEjijl32f3ZEmiHekebRggPdPjhHI6t1CsAQOR2Aw/SuTDftk3/l2aaPHpwP3xM2DkgBA1ANw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.9.0 <1.10.0' + + '@opentelemetry/sdk-node@0.210.0': + resolution: {integrity: sha512-KymqUtYvfpblDNgGxBXYqCcDjYXwjOF7Muc6ocs0rMlG/66Hcs9KiJ7hg4zLOv63JubF/vxi5WXaLrQrPKyaZQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.10.0': + resolution: {integrity: sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.4.0': + resolution: {integrity: sha512-WH0xXkz/OHORDLKqaxcUZS0X+t1s7gGlumr2ebiEgNZQl2b0upK2cdoD0tatf7l8iP74woGJ/Kmxe82jdvcWRw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-node@2.10.0': + resolution: {integrity: sha512-GZK/G6oZyBLGlH1pUgeDch7D91KoHd2uotUGIkWCPi9GI5T9X0p4L7nNAMDR1BQjkRYoDqo+ddfVx9t5Uhys+Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/sdk-trace-node@2.4.0': + resolution: {integrity: sha512-MBc2l04hZPYygnWPT38UiOPy9ueutPqmJ47z0m9IKuoVQh3MblmbSgwspjhdHagZLfSfmlzhWR1xtbgVNmjX2A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/sdk-trace@2.10.0': + resolution: {integrity: sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.43.0': + resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} + engines: {node: '>=14'} + '@oxc-project/types@0.124.0': resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} @@ -4113,6 +4407,9 @@ packages: '@protobufjs/float@1.0.2': resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + '@protobufjs/inquire@1.1.2': + resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==} + '@protobufjs/path@1.1.2': resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} @@ -4301,6 +4598,39 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@rushstack/node-core-library@5.24.0': + resolution: {integrity: sha512-g/Z47ZwARn/VkTnHcyJslrR26erRf1G5JbqPlfGZGBCrOcrEt8fTQXXDVhUDDNl/g/v3TXI1dNiAAT5FEks8BA==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/problem-matcher@0.2.1': + resolution: {integrity: sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.7.3': + resolution: {integrity: sha512-aAA518n6wxxjCfnTAOjQnm7ngNE0FVHxHAw2pxKlIhxrMn0XQjGcXKF0oKWpjBgJOmsaJpVob/v+zr3zxgPWuA==} + + '@rushstack/terminal@0.24.3': + resolution: {integrity: sha512-KxphDhPGC4xDrKg8O4yrWCEpPMi87aJc1iycXqMVh1dLgV0M34hiH9ZTgWjBRmcrT/OIHoOeWf48npcQFzgp+g==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/ts-command-line@5.3.13': + resolution: {integrity: sha512-+jNbxhh8CkrZYxMk9X3GRYM2+Myr1xCCj+eHbJ9Vp+PCdNHS0TUl5QQFT6UbM/aTFRCzs5jiBTKYzBRpe5uYbQ==} + engines: {node: '>=20.9.0'} + '@sapphire/async-queue@1.5.5': resolution: {integrity: sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} @@ -4728,6 +5058,9 @@ packages: '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + '@types/body-parser@1.19.6': resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} @@ -5491,6 +5824,11 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + acorn-import-phases@1.0.4: resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} engines: {node: '>=10.13.0'} @@ -5544,6 +5882,14 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -5576,6 +5922,9 @@ packages: ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + algoliasearch-helper@3.28.1: resolution: {integrity: sha512-6iXpbkkrAI5HFpCWXlNmIDSBuoN/U1XnEvb2yJAoWfqrZ+DrybI7MQ5P5mthFaprmocq+zbi6HxnR28xnZAYBw==} peerDependencies: @@ -5645,6 +5994,9 @@ packages: arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -6169,6 +6521,9 @@ packages: resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} engines: {node: '>= 0.10'} + cjs-module-lexer@2.2.1: + resolution: {integrity: sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==} + clean-css@5.3.3: resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} engines: {node: '>= 10.0'} @@ -7036,6 +7391,10 @@ packages: devtools-protocol@0.0.1666840: resolution: {integrity: sha512-gCcO42XCHKEs7Ag0S7aGYsnJ7hlgrO3qderYqeiY0Eqk+0GFfuvT13IA0hHreJTa2KCdDVyGMeOhdMNmrrTjVg==} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} @@ -8405,6 +8764,9 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + import-in-the-middle@2.0.6: + resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==} + import-lazy@4.0.0: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} engines: {node: '>=8'} @@ -8830,6 +9192,9 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + joi@17.13.4: resolution: {integrity: sha512-1RuuER6kmt8K8I3nIWvPZKi5RQCb568ZPyY4Pwjlua+yo+63ZTmIwxLZH0heBmiKN4uxjvCiarDrjaeH84xicQ==} @@ -9275,6 +9640,9 @@ packages: lodash-es@4.18.1: resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -9807,6 +10175,9 @@ packages: resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} engines: {node: '>=0.10.0'} + module-details-from-path@1.0.4: + resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + mri@1.1.4: resolution: {integrity: sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==} engines: {node: '>=4'} @@ -11009,6 +11380,10 @@ packages: resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} engines: {node: '>=12.0.0'} + protobufjs@8.0.0: + resolution: {integrity: sha512-jx6+sE9h/UryaCZhsJWbJtTEy47yXoGNYI4z8ZaRncM0zBKeRqjO2JEcOUYwrYGb1WLhXM1FfMzW3annvFv0rw==} + engines: {node: '>=12.0.0'} + protocols@2.0.2: resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} @@ -11415,6 +11790,10 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-in-the-middle@8.0.1: + resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} + engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} + require-like@0.1.2: resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} @@ -11857,6 +12236,9 @@ packages: split@1.0.1: resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + srcset@4.0.0: resolution: {integrity: sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==} engines: {node: '>=12'} @@ -14269,13 +14651,13 @@ snapshots: transitivePeerDependencies: - encoding - '@browserbasehq/stagehand@3.0.7(@cfworker/json-schema@4.1.1)(@opentelemetry/api@1.9.0)(deepmerge@4.3.1)(dotenv@16.4.7)(encoding@0.1.13)(supports-color@8.1.1)(zod@4.4.3)': + '@browserbasehq/stagehand@3.0.7(@cfworker/json-schema@4.1.1)(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(deepmerge@4.3.1)(dotenv@16.4.7)(encoding@0.1.13)(supports-color@8.1.1)(zod@4.4.3)': dependencies: '@ai-sdk/provider': 2.0.1 '@anthropic-ai/sdk': 0.39.0(encoding@0.1.13) '@browserbasehq/sdk': 2.10.0(encoding@0.1.13) '@google/genai': 1.50.0(@modelcontextprotocol/sdk@1.29.0(@cfworker/json-schema@4.1.1)(supports-color@7.2.0)(zod@4.4.3))(bufferutil@4.1.0)(supports-color@8.1.1) - '@langchain/openai': 0.4.9(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)))(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0)) + '@langchain/openai': 0.4.9(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)))(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0)) '@modelcontextprotocol/sdk': 1.29.0(@cfworker/json-schema@4.1.1)(supports-color@7.2.0)(zod@4.4.3) ai: 5.0.173(zod@4.4.3) deepmerge: 4.3.1 @@ -14302,7 +14684,7 @@ snapshots: '@ai-sdk/perplexity': 2.0.27(zod@4.4.3) '@ai-sdk/togetherai': 1.0.38(zod@4.4.3) '@ai-sdk/xai': 2.0.67(zod@4.4.3) - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)) + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)) bufferutil: 4.1.0 chrome-launcher: 1.2.1(supports-color@7.2.0) ollama-ai-provider-v2: 1.5.5(zod@4.4.3) @@ -15827,6 +16209,18 @@ snapshots: - supports-color - utf-8-validate + '@grpc/grpc-js@1.14.4': + dependencies: + '@grpc/proto-loader': 0.8.1 + '@js-sdsl/ordered-map': 4.4.2 + + '@grpc/proto-loader@0.8.1': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.6.5 + yargs: 17.7.2 + '@hapi/hoek@9.3.0': {} '@hapi/topo@5.1.0': @@ -16039,6 +16433,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@js-sdsl/ordered-map@4.4.2': {} + '@jsonjoy.com/base64@1.1.2(tslib@2.8.1)': dependencies: tslib: 2.8.1 @@ -16168,14 +16564,14 @@ snapshots: '@keyv/serialize@1.1.1': {} - '@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3))': + '@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3))': dependencies: '@cfworker/json-schema': 4.1.1 ansi-styles: 5.2.0 camelcase: 6.3.0 decamelize: 1.2.0 js-tiktoken: 1.0.21 - langsmith: 0.3.87(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)) + langsmith: 0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)) mustache: 4.2.0 p-queue: 6.6.2 p-retry: 4.6.2 @@ -16188,9 +16584,9 @@ snapshots: - '@opentelemetry/sdk-trace-base' - openai - '@langchain/openai@0.4.9(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)))(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))': + '@langchain/openai@0.4.9(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)))(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))': dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)) + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)) js-tiktoken: 1.0.21 openai: 4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@3.25.76) zod: 3.25.76 @@ -16247,6 +16643,41 @@ snapshots: dependencies: '@chevrotain/types': 11.1.2 + '@microsoft/api-extractor-model@7.33.11(@types/node@24.12.2)': + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': 5.24.0(@types/node@24.12.2) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.59.0(@types/node@24.12.2)': + dependencies: + '@microsoft/api-extractor-model': 7.33.11(@types/node@24.12.2) + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': 5.24.0(@types/node@24.12.2) + '@rushstack/rig-package': 0.7.3 + '@rushstack/terminal': 0.24.3(@types/node@24.12.2) + '@rushstack/ts-command-line': 5.3.13(@types/node@24.12.2) + diff: 8.0.4 + minimatch: 9.0.9 + resolve: 1.22.12 + semver: 7.7.4 + source-map: 0.6.1 + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/tsdoc-config@0.18.1': + dependencies: + '@microsoft/tsdoc': 0.16.0 + ajv: 8.18.0 + jju: 1.4.0 + resolve: 1.22.12 + + '@microsoft/tsdoc@0.16.0': {} + '@modelcontextprotocol/sdk@1.29.0(@cfworker/json-schema@4.1.1)(supports-color@7.2.0)(zod@4.4.3)': dependencies: '@hono/node-server': 1.19.17(hono@4.13.3) @@ -16613,8 +17044,287 @@ snapshots: '@open-draft/until@2.1.0': {} + '@opentelemetry/api-logs@0.210.0': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api@1.9.0': {} + '@opentelemetry/configuration@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + yaml: 2.9.0 + + '@opentelemetry/context-async-hooks@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + + '@opentelemetry/context-async-hooks@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + + '@opentelemetry/core@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/core@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/exporter-logs-otlp-grpc@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@grpc/grpc-js': 1.14.4 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.210.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-logs-otlp-http@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.210.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.210.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-logs-otlp-proto@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.210.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-metrics-otlp-grpc@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@grpc/grpc-js': 1.14.4 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-metrics-otlp-http@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-metrics-otlp-proto@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-prometheus@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-trace-otlp-grpc@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@grpc/grpc-js': 1.14.4 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-trace-otlp-http@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-zipkin@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/instrumentation@0.210.0(@opentelemetry/api@1.9.0)(supports-color@7.2.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.210.0 + import-in-the-middle: 2.0.6 + require-in-the-middle: 8.0.1(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation@0.210.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.210.0 + import-in-the-middle: 2.0.6 + require-in-the-middle: 8.0.1(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/otlp-exporter-base@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/otlp-grpc-exporter-base@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@grpc/grpc-js': 1.14.4 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.210.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/otlp-transformer@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.210.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.4.0(@opentelemetry/api@1.9.0) + protobufjs: 8.0.0 + + '@opentelemetry/propagator-b3@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/propagator-jaeger@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/resources@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/sdk-logs@0.210.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.210.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-metrics@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-node@0.210.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.210.0 + '@opentelemetry/configuration': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/context-async-hooks': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-grpc': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-http': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-proto': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-grpc': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-proto': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-prometheus': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-grpc': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-http': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-proto': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-zipkin': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.210.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1) + '@opentelemetry/propagator-b3': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-jaeger': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/sdk-trace-node@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.10.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-trace-node@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-trace@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/semantic-conventions@1.43.0': {} + '@oxc-project/types@0.124.0': {} '@oxfmt/binding-android-arm-eabi@0.46.0': @@ -16883,6 +17593,8 @@ snapshots: '@protobufjs/float@1.0.2': {} + '@protobufjs/inquire@1.1.2': {} + '@protobufjs/path@1.1.2': {} '@protobufjs/pool@1.1.0': {} @@ -17000,6 +17712,45 @@ snapshots: '@rtsao/scc@1.1.0': {} + '@rushstack/node-core-library@5.24.0(@types/node@24.12.2)': + dependencies: + ajv: 8.20.0 + ajv-draft-04: 1.0.0(ajv@8.20.0) + ajv-formats: 3.0.1(ajv@8.20.0) + fs-extra: 11.3.4 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.12 + semver: 7.7.4 + optionalDependencies: + '@types/node': 24.12.2 + + '@rushstack/problem-matcher@0.2.1(@types/node@24.12.2)': + optionalDependencies: + '@types/node': 24.12.2 + + '@rushstack/rig-package@0.7.3': + dependencies: + jju: 1.4.0 + resolve: 1.22.12 + + '@rushstack/terminal@0.24.3(@types/node@24.12.2)': + dependencies: + '@rushstack/node-core-library': 5.24.0(@types/node@24.12.2) + '@rushstack/problem-matcher': 0.2.1(@types/node@24.12.2) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 24.12.2 + + '@rushstack/ts-command-line@5.3.13(@types/node@24.12.2)': + dependencies: + '@rushstack/terminal': 0.24.3(@types/node@24.12.2) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + '@sapphire/async-queue@1.5.5': {} '@sec-ant/readable-stream@0.4.1': {} @@ -17395,6 +18146,8 @@ snapshots: dependencies: tslib: 2.8.1 + '@types/argparse@1.0.38': {} + '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 @@ -18180,6 +18933,10 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -18231,6 +18988,10 @@ snapshots: '@opentelemetry/api': 1.9.0 zod: 4.4.3 + ajv-draft-04@1.0.0(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv-formats@2.1.1(ajv@8.18.0): optionalDependencies: ajv: 8.18.0 @@ -18239,6 +19000,10 @@ snapshots: optionalDependencies: ajv: 8.18.0 + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv-keywords@3.5.2(ajv@6.14.0): dependencies: ajv: 6.14.0 @@ -18262,6 +19027,13 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.5 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + algoliasearch-helper@3.28.1(algoliasearch@5.50.1): dependencies: '@algolia/events': 4.0.1 @@ -18401,6 +19173,10 @@ snapshots: arg@5.0.2: {} + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + argparse@2.0.1: {} args@5.0.3: @@ -19111,6 +19887,8 @@ snapshots: safe-buffer: 5.2.1 to-buffer: 1.2.2 + cjs-module-lexer@2.2.1: {} + clean-css@5.3.3: dependencies: source-map: 0.6.1 @@ -20047,6 +20825,8 @@ snapshots: devtools-protocol@0.0.1666840: {} + diff@8.0.4: {} + diffie-hellman@5.0.3: dependencies: bn.js: 4.12.3 @@ -22005,6 +22785,13 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-in-the-middle@2.0.6: + dependencies: + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + cjs-module-lexer: 2.2.1 + module-details-from-path: 1.0.4 + import-lazy@4.0.0: {} import-local@3.1.0: @@ -22387,6 +23174,8 @@ snapshots: jiti@2.6.1: {} + jju@1.4.0: {} + joi@17.13.4: dependencies: '@hapi/hoek': 9.3.0 @@ -22564,7 +23353,7 @@ snapshots: kuler@2.0.0: {} - langsmith@0.3.87(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)): + langsmith@0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.210.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(openai@4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3)): dependencies: '@types/uuid': 10.0.0 chalk: 4.1.2 @@ -22574,6 +23363,8 @@ snapshots: uuid: 10.0.0 optionalDependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/exporter-trace-otlp-proto': 0.210.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.10.0(@opentelemetry/api@1.9.0) openai: 4.104.0(encoding@0.1.13)(ws@8.21.3(bufferutil@4.1.0))(zod@4.4.3) language-subtag-registry@0.3.23: {} @@ -22896,6 +23687,8 @@ snapshots: lodash-es@4.18.1: {} + lodash.camelcase@4.3.0: {} + lodash.debounce@4.0.8: {} lodash.isequal@4.5.0: {} @@ -23772,6 +24565,8 @@ snapshots: modify-values@1.0.1: {} + module-details-from-path@1.0.4: {} + mri@1.1.4: {} mrmime@2.0.1: {} @@ -25307,6 +26102,21 @@ snapshots: '@types/node': 24.12.2 long: 5.3.2 + protobufjs@8.0.0: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.2 + '@types/node': 24.12.2 + long: 5.3.2 + protocols@2.0.2: {} proxy-addr@2.0.7: @@ -25882,6 +26692,20 @@ snapshots: require-from-string@2.0.2: {} + require-in-the-middle@8.0.1(supports-color@7.2.0): + dependencies: + debug: 4.4.3(supports-color@7.2.0) + module-details-from-path: 1.0.4 + transitivePeerDependencies: + - supports-color + + require-in-the-middle@8.0.1(supports-color@8.1.1): + dependencies: + debug: 4.4.3(supports-color@8.1.1) + module-details-from-path: 1.0.4 + transitivePeerDependencies: + - supports-color + require-like@0.1.2: {} requires-port@1.0.0: {} @@ -26467,6 +27291,8 @@ snapshots: dependencies: through: 2.3.8 + sprintf-js@1.0.3: {} + srcset@4.0.0: {} ssri@12.0.0: diff --git a/test/otel/fixtures/crawler.ts b/test/otel/fixtures/crawler.ts new file mode 100644 index 000000000000..aea983825143 --- /dev/null +++ b/test/otel/fixtures/crawler.ts @@ -0,0 +1,14 @@ +import { CheerioCrawler } from '@crawlee/cheerio'; +import { MemoryStorageBackend, serviceLocator } from '@crawlee/core'; + +import log from '@apify/log'; + +log.setLevel(log.LEVELS.OFF); +serviceLocator.setStorageBackend(new MemoryStorageBackend()); + +const crawler = new CheerioCrawler({ + maxRequestRetries: 0, + requestHandler: async () => {}, +}); + +await crawler.run([process.env.CRAWLEE_OTEL_SMOKE_URL!]); diff --git a/test/otel/fixtures/otel-setup.ts b/test/otel/fixtures/otel-setup.ts new file mode 100644 index 000000000000..35a62c3ed6c5 --- /dev/null +++ b/test/otel/fixtures/otel-setup.ts @@ -0,0 +1,23 @@ +import { writeFileSync } from 'node:fs'; + +import { CrawleeInstrumentation } from '@crawlee/otel'; +import { NodeSDK } from '@opentelemetry/sdk-node'; +import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; + +const exporter = new InMemorySpanExporter(); + +const sdk = new NodeSDK({ + spanProcessors: [new SimpleSpanProcessor(exporter)], + instrumentations: [new CrawleeInstrumentation({ logInstrumentation: false })], +}); + +sdk.start(); + +// `SimpleSpanProcessor` hands every span over as it ends, so by the time the process is on its way out the exporter +// holds everything. Written from `exit` so the crawler script itself stays a plain crawler, exactly like the guide's. +process.on('exit', () => { + const output = process.env.CRAWLEE_OTEL_SMOKE_OUTPUT; + if (output) { + writeFileSync(output, JSON.stringify(exporter.getFinishedSpans().map((span) => span.name))); + } +}); diff --git a/test/otel/fixtures/register-hook.ts b/test/otel/fixtures/register-hook.ts new file mode 100644 index 000000000000..e6788e175f7a --- /dev/null +++ b/test/otel/fixtures/register-hook.ts @@ -0,0 +1,6 @@ +import { register } from 'node:module'; +import { pathToFileURL } from 'node:url'; + +// Identical to the guide's own hook file: this is the delivery mechanism the automatic instrumentation depends on, +// and the only reason this fixture exists as a separate preload is that ESM imports are hoisted. +register('@opentelemetry/instrumentation/hook.mjs', pathToFileURL('./')); diff --git a/test/otel/hook-delivery.test.ts b/test/otel/hook-delivery.test.ts new file mode 100644 index 000000000000..885f07721062 --- /dev/null +++ b/test/otel/hook-delivery.test.ts @@ -0,0 +1,68 @@ +import { execFile } from 'node:child_process'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import type { Server } from 'node:http'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import { runExampleComServer } from '../shared/_helper.js'; + +/** + * Runs the instrumentation the way a user does: through Node's module hook, in a process that was never told about + * the instrumentation in its own code. + * + * The other tests in this directory apply the module patches by hand, which covers what the patches do but not + * whether they are ever delivered. Delivery has its own failure mode: the hook has to be registered before anything + * imports Crawlee, and nothing inside the crawler's own process can tell that it was not. + * + * The fixtures are deliberately the same three files the guide tells users to write, so this also fails if the guide's + * setup stops working. + */ +describe('module hook delivery', () => { + const root = resolve(__dirname, '../..'); + const fixture = (name: string) => `./${join('test/otel/fixtures', name)}`; + + let server: Server; + let serverAddress: string; + let outputDir: string; + + beforeAll(async () => { + const [startedServer, port] = await runExampleComServer(); + server = startedServer; + serverAddress = `http://localhost:${port}`; + outputDir = mkdtempSync(join(tmpdir(), 'crawlee-otel-')); + }); + + afterAll(async () => { + rmSync(outputDir, { recursive: true, force: true }); + await new Promise((done) => server.close(done)); + }); + + test('instruments a crawler that only ever imports Crawlee', async () => { + const output = join(outputDir, 'spans.json'); + + await promisify(execFile)( + join(root, 'node_modules/.bin/tsx'), + ['--import', fixture('register-hook.ts'), '--import', fixture('otel-setup.ts'), fixture('crawler.ts')], + { + cwd: root, + env: { + ...process.env, + CRAWLEE_OTEL_SMOKE_OUTPUT: output, + CRAWLEE_OTEL_SMOKE_URL: serverAddress, + }, + }, + ); + + const spans = JSON.parse(readFileSync(output, 'utf8')) as string[]; + + // One span from each patched module that a `CheerioCrawler` run reaches, so a hook that never fires + // shows up as an empty list rather than as a silently smaller trace. + expect(spans.sort()).toEqual([ + 'crawlee.crawler.handleRequest', + 'crawlee.crawler.run', + 'crawlee.crawler.runRequestHandler', + 'crawlee.http.makeHttpRequest', + ]); + }, 180_000); // A cold child process has to load and transpile the whole crawler dependency graph. +}); diff --git a/test/otel/instrumentation.test.ts b/test/otel/instrumentation.test.ts new file mode 100644 index 000000000000..04cce244324c --- /dev/null +++ b/test/otel/instrumentation.test.ts @@ -0,0 +1,192 @@ +import type { Server } from 'node:http'; + +import * as basicModule from '@crawlee/basic'; +import { CheerioCrawler } from '@crawlee/cheerio'; +import { MemoryStorageBackend, serviceLocator } from '@crawlee/core'; +import * as httpModule from '@crawlee/http'; +import { CrawleeInstrumentation } from '@crawlee/otel'; +import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'; +import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; +import { ATTR_CODE_FUNCTION_NAME, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from '@opentelemetry/semantic-conventions'; + +import log from '@apify/log'; + +import { runExampleComServer } from '../shared/_helper.js'; + +/** + * Drives a real crawler through the real instrumented Crawlee classes. + * + * The module patches are applied directly rather than through Node's module hook, which would otherwise have to be + * registered before Vitest loads any Crawlee module. Only the delivery of the patch is bypassed - everything the + * instrumentation itself does (which prototypes get wrapped, the span tree, the attributes, error handling, context + * propagation across the crawler's async boundaries) is exercised here. The hook path is covered by running the + * guide's own examples; see docs/guides/trace-and-monitor-crawlers.mdx. + */ +interface PatchableModuleDefinition { + name: string; + patch: (moduleExports: unknown) => unknown; + unpatch: (moduleExports: unknown) => unknown; +} + +function moduleDefinition(instrumentation: CrawleeInstrumentation, moduleName: string): PatchableModuleDefinition { + const definitions = (instrumentation as any).init() as PatchableModuleDefinition[]; + const definition = definitions.find((d) => d.name === moduleName); + + if (!definition) { + throw new Error(`No instrumentation definition for ${moduleName}`); + } + + return definition; +} + +describe('CrawleeInstrumentation against a real crawler', () => { + let server: Server; + let serverAddress: string; + let logLevel: number; + + let exporter: InMemorySpanExporter; + let provider: NodeTracerProvider; + let patched: { definition: PatchableModuleDefinition; moduleExports: unknown }[]; + + beforeAll(async () => { + logLevel = log.getLevel(); + // Two of these tests fail requests on purpose; silence the crawler's own error reporting. + log.setLevel(log.LEVELS.OFF); + + const [startedServer, port] = await runExampleComServer(); + server = startedServer; + serverAddress = `http://localhost:${port}`; + + exporter = new InMemorySpanExporter(); + provider = new NodeTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] }); + provider.register(); + + const instrumentation = new CrawleeInstrumentation({ logInstrumentation: false }); + instrumentation.setTracerProvider(provider); + patched = [ + { definition: moduleDefinition(instrumentation, '@crawlee/basic'), moduleExports: basicModule }, + { definition: moduleDefinition(instrumentation, '@crawlee/http'), moduleExports: httpModule }, + ]; + + for (const { definition, moduleExports } of patched) { + definition.patch(moduleExports); + } + }); + + afterAll(async () => { + for (const { definition, moduleExports } of patched) { + definition.unpatch(moduleExports); + } + + await provider.shutdown(); + server.close(); + log.setLevel(logLevel); + }); + + beforeEach(() => { + exporter.reset(); + serviceLocator.setStorageBackend(new MemoryStorageBackend()); + }); + + const byName = (spans: ReadableSpan[], name: string) => spans.filter((s) => s.name === name); + const one = (spans: ReadableSpan[], name: string) => { + const found = byName(spans, name); + expect(found, `expected exactly one ${name} span, got ${found.length}`).toHaveLength(1); + return found[0]; + }; + + test('produces a nested span tree for a successful request', async () => { + let seenUrl: string | undefined; + + const crawler = new CheerioCrawler({ + maxRequestsPerCrawl: 1, + async requestHandler({ $, request }) { + expect($('title').text()).toBe('Example Domain'); + seenUrl = request.url; + }, + }); + + await crawler.run([serverAddress]); + + const spans = exporter.getFinishedSpans(); + + expect(spans.length).toBeGreaterThan(0); + expect(new Set(spans.map((s) => (s.instrumentationScope ?? (s as any).instrumentationLibrary)?.name))).toEqual( + new Set(['@crawlee/otel']), + ); + + const run = one(spans, 'crawlee.crawler.run'); + const handleRequest = one(spans, 'crawlee.crawler.handleRequest'); + const requestHandler = one(spans, 'crawlee.crawler.runRequestHandler'); + const httpRequest = one(spans, 'crawlee.http.makeHttpRequest'); + + // A single trace, correctly nested - this only holds if the context survives the crawler's async boundaries. + expect(new Set(spans.map((s) => s.spanContext().traceId)).size).toBe(1); + expect(handleRequest.parentSpanContext?.spanId).toBe(run.spanContext().spanId); + expect(requestHandler.parentSpanContext?.spanId).toBe(handleRequest.spanContext().spanId); + + // Nothing failed, so the instrumentation leaves the status unset. + expect(requestHandler.status.code).toBe(0); + + expect(run.attributes['crawlee.crawler.type']).toBe('CheerioCrawler'); + expect(seenUrl).toBeDefined(); + expect(requestHandler.attributes).toMatchObject({ + [ATTR_URL_FULL]: seenUrl, + [ATTR_HTTP_REQUEST_METHOD]: 'GET', + [ATTR_CODE_FUNCTION_NAME]: 'BasicCrawler.runRequestHandler', + 'crawlee.request.retry_count': 0, + }); + expect(requestHandler.attributes['crawlee.request.id']).toEqual(expect.any(String)); + expect(httpRequest.attributes[ATTR_URL_FULL]).toBe(seenUrl); + }); + + test('records the failure on the request handler span and on the error handlers', async () => { + let seenUrl: string | undefined; + + const crawler = new CheerioCrawler({ + maxRequestsPerCrawl: 1, + maxRequestRetries: 0, + requestHandler({ request }) { + seenUrl = request.url; + throw new Error('handler exploded'); + }, + }); + + await crawler.run([serverAddress]); + + const spans = exporter.getFinishedSpans(); + + const requestHandler = one(spans, 'crawlee.crawler.runRequestHandler'); + expect(requestHandler.status.code).toBe(2); // SpanStatusCode.ERROR + expect(requestHandler.status.message).toBe('handler exploded'); + expect(requestHandler.events.map((e) => e.name)).toContain('exception'); + + // Both error handling methods are instrumented, and both report which request failed. + const errorHandler = one(spans, 'crawlee.crawler.requestFunctionErrorHandler'); + const failedHandler = one(spans, 'crawlee.crawler.handleFailedRequestHandler'); + expect(seenUrl).toBeDefined(); + expect(errorHandler.attributes[ATTR_URL_FULL]).toBe(seenUrl); + expect(failedHandler.attributes[ATTR_URL_FULL]).toBe(seenUrl); + + expect(requestHandler.spanContext().traceId).toBe(errorHandler.spanContext().traceId); + }); + + test('increments the retry count attribute across attempts', async () => { + const crawler = new CheerioCrawler({ + maxRequestsPerCrawl: 1, + maxRequestRetries: 1, + requestHandler() { + throw new Error('always fails'); + }, + }); + + await crawler.run([serverAddress]); + + const retryCounts = byName(exporter.getFinishedSpans(), 'crawlee.crawler.runRequestHandler') + .map((s) => s.attributes['crawlee.request.retry_count']) + .sort(); + + expect(retryCounts).toEqual([0, 1]); + }); +}); diff --git a/test/otel/log-forwarding.test.ts b/test/otel/log-forwarding.test.ts new file mode 100644 index 000000000000..cf97e8638216 --- /dev/null +++ b/test/otel/log-forwarding.test.ts @@ -0,0 +1,93 @@ +import { BasicCrawler } from '@crawlee/basic'; +import * as coreModule from '@crawlee/core'; +import { CrawleeInstrumentation } from '@crawlee/otel'; +import { SeverityNumber } from '@opentelemetry/api-logs'; +import { InMemoryLogRecordExporter, LoggerProvider, SimpleLogRecordProcessor } from '@opentelemetry/sdk-logs'; +import { ATTR_EXCEPTION_MESSAGE, ATTR_EXCEPTION_TYPE } from '@opentelemetry/semantic-conventions'; + +/** + * Forwards logs from the real `@crawlee/core` logger, patched the same way the module hook would patch it. + * + * The patch targets `BaseCrawleeLogger`, which every Crawlee logger derives from, so this also covers a Winston, Pino + * or hand-written adapter - only `logWithLevel` differs between them. + */ +describe('log forwarding against the real Crawlee logger', () => { + let exporter: InMemoryLogRecordExporter; + let loggerProvider: LoggerProvider; + let definition: { patch: (e: unknown) => unknown; unpatch: (e: unknown) => unknown }; + + beforeAll(() => { + exporter = new InMemoryLogRecordExporter(); + loggerProvider = new LoggerProvider({ processors: [new SimpleLogRecordProcessor(exporter)] }); + + const instrumentation = new CrawleeInstrumentation({ requestHandlingInstrumentation: false }); + instrumentation.setLoggerProvider(loggerProvider); + + definition = (instrumentation as any).init().find((d: any) => d.name === '@crawlee/core'); + definition.patch(coreModule); + }); + + afterAll(async () => { + definition.unpatch(coreModule); + await loggerProvider.shutdown(); + }); + + beforeEach(() => exporter.reset()); + + test('forwards a log made through the default Crawlee logger', () => { + const log = new coreModule.ApifyLogAdapter(coreModule.log); + + log.info('hello from crawlee', { page: 3 }); + + const records = exporter.getFinishedLogRecords(); + expect(records).toHaveLength(1); + expect(records[0].body).toBe('hello from crawlee'); + expect(records[0].severityNumber).toBe(SeverityNumber.INFO); + expect(records[0].severityText).toBe('INFO'); + expect(records[0].attributes).toMatchObject({ page: 3 }); + }); + + test('records an exception on the semantic convention attributes', () => { + const log = new coreModule.ApifyLogAdapter(coreModule.log); + + log.exception(new RangeError('out of range'), 'request failed'); + + const record = exporter.getFinishedLogRecords()[0]; + expect(record.severityNumber).toBe(SeverityNumber.ERROR); + expect(record.attributes[ATTR_EXCEPTION_TYPE]).toBe('RangeError'); + expect(record.attributes[ATTR_EXCEPTION_MESSAGE]).toBe('out of range'); + }); + + test('forwards a crawler status message', () => { + coreModule.serviceLocator.setStorageBackend(new coreModule.MemoryStorageBackend()); + const crawler = new BasicCrawler({ requestHandler: async () => {} }); + exporter.reset(); + + crawler.setStatusMessage('Crawled 40/100 pages, 2 failed.', { level: 'INFO' }); + + // `setStatusMessage` is the one place in Crawlee that logs at a level chosen at runtime. It used to reach for + // `logWithLevel`, which is abstract on `BaseCrawleeLogger` and so cannot be patched - the periodic status + // messages never reached OpenTelemetry at all. + const record = exporter.getFinishedLogRecords().at(-1)!; + expect(record.body).toBe('Crawled 40/100 pages, 2 failed.'); + expect(record.severityNumber).toBe(SeverityNumber.INFO); + }); + + test('maps each level onto the matching severity', () => { + const log = new coreModule.ApifyLogAdapter(coreModule.log); + + log.error('e'); + log.softFail('s'); + log.warning('w'); + log.debug('d'); + log.perf('p'); + + expect(exporter.getFinishedLogRecords().map((r) => r.severityNumber)).toEqual([ + SeverityNumber.ERROR, + SeverityNumber.WARN, + SeverityNumber.WARN, + SeverityNumber.DEBUG, + SeverityNumber.DEBUG, + ]); + }); +}); diff --git a/test/otel/patched-methods.test.ts b/test/otel/patched-methods.test.ts new file mode 100644 index 000000000000..191002a161ff --- /dev/null +++ b/test/otel/patched-methods.test.ts @@ -0,0 +1,52 @@ +import * as basicModule from '@crawlee/basic'; +import * as browserModule from '@crawlee/browser'; +import * as coreModule from '@crawlee/core'; +import * as httpModule from '@crawlee/http'; +import * as playwrightModule from '@crawlee/playwright'; + +import { loggerMethods, requestHandlingInstrumentationMethods } from '../../packages/otel/src/constants.js'; + +/** + * Asserts that every method the automatic instrumentation patches by name still exists on the real prototype. + * + * Most of them are TypeScript `private`, so renaming one is a routine refactor - and a rename is invisible at runtime: + * the instrumentation reports the missing method through `diag`, which is a no-op unless the application installed a + * diagnostic logger, and then carries on unpatched. The span or log record simply stops being recorded. + * + * This is the tripwire. It fails in the same pull request as the rename, and names the method that moved, so the + * instrumented methods can stay private instead of being promoted to `protected` for the instrumentation's sake. + */ +const instrumentedModules: Record> = { + '@crawlee/basic': basicModule, + '@crawlee/browser': browserModule, + '@crawlee/core': coreModule, + '@crawlee/http': httpModule, + '@crawlee/playwright': playwrightModule, +}; + +describe('the patched Crawlee methods still exist', () => { + test.each( + requestHandlingInstrumentationMethods.map( + (method) => [method.moduleName, method.className, method.methodName] as const, + ), + )('%s exports %s with a %s method', (moduleName, className, methodName) => { + const moduleExports = instrumentedModules[moduleName]; + expect(moduleExports, `${moduleName} is instrumented but not covered by this test`).toBeDefined(); + + const patchedClass = moduleExports[className] as { prototype?: Record } | undefined; + expect(patchedClass?.prototype, `${moduleName} no longer exports ${className}`).toBeDefined(); + expect(typeof patchedClass!.prototype![methodName], `${className}.${methodName} is no longer a method`).toBe( + 'function', + ); + }); + + test.each(loggerMethods.map((method) => [method.methodName] as const))( + '@crawlee/core exports BaseCrawleeLogger with a %s method', + (methodName) => { + const prototype = coreModule.BaseCrawleeLogger.prototype as unknown as Record; + expect(typeof prototype[methodName], `BaseCrawleeLogger.${methodName} is no longer a method`).toBe( + 'function', + ); + }, + ); +}); diff --git a/test/otel/tracer-wiring.test.ts b/test/otel/tracer-wiring.test.ts new file mode 100644 index 000000000000..b3360d700b04 --- /dev/null +++ b/test/otel/tracer-wiring.test.ts @@ -0,0 +1,66 @@ +import { CrawleeInstrumentation, wrapWithSpan } from '@crawlee/otel'; +import { registerInstrumentations } from '@opentelemetry/instrumentation'; +import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'; +import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; + +// Reached directly rather than through the package entry point: resetting the shared tracer is not public API. +import { setSharedTracer } from '../../packages/otel/src/wrapWithSpan.js'; + +/** + * The instrumentation is always constructed before the SDK is configured, so these tests cover that ordering for + * both ways a provider reaches it: registered globally, or handed over explicitly. The explicit case used to emit + * nothing at all, because the tracer was taken from the global API in the constructor and that provider never gets + * a delegate when the SDK does not register itself globally. + */ +describe('tracer wiring', () => { + const scopeOf = (span: ReadableSpan) => (span.instrumentationScope ?? (span as any).instrumentationLibrary)?.name; + + // `wrapWithSpan` shares one tracer per process, so a test that asserts the fallback has to start from a clean one + // no matter which of these ran first. + beforeEach(() => setSharedTracer(undefined)); + + test('emits spans when the provider is registered globally', async () => { + const exporter = new InMemorySpanExporter(); + + const instrumentation = new CrawleeInstrumentation({ logInstrumentation: false }); + void instrumentation; + + const provider = new NodeTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] }); + provider.register(); + + try { + wrapWithSpan(() => 'value', { spanName: 'global-provider' })(); + + const spans = exporter.getFinishedSpans(); + expect(spans.map((s) => s.name)).toEqual(['global-provider']); + expect(scopeOf(spans[0])).toBe('@crawlee/otel'); + } finally { + await provider.shutdown(); + } + }); + + test('emits spans when the provider is passed to registerInstrumentations instead of registered', async () => { + const exporter = new InMemorySpanExporter(); + + // Constructed before the provider exists, and the provider is never registered globally. + const instrumentation = new CrawleeInstrumentation({ logInstrumentation: false }); + const provider = new NodeTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] }); + + const unregister = registerInstrumentations({ + instrumentations: [instrumentation], + tracerProvider: provider, + }); + + try { + wrapWithSpan(() => 'value', { spanName: 'explicit-provider' })(); + + const spans = exporter.getFinishedSpans(); + expect(spans.map((s) => s.name)).toEqual(['explicit-provider']); + expect(scopeOf(spans[0])).toBe('@crawlee/otel'); + } finally { + unregister(); + await provider.shutdown(); + } + }); +}); diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index b9329311ff31..07ebaeae5b7f 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -20,6 +20,7 @@ const packages = [ 'types', 'impit-client', 'got-scraping-client', + 'otel', ]; const packagesOrder = [ '@crawlee/core', @@ -39,6 +40,7 @@ const packagesOrder = [ '@crawlee/types', '@crawlee/impit-client', '@crawlee/got-scraping-client', + '@crawlee/otel', ]; /** @type {Partial} */ diff --git a/website/sidebars.js b/website/sidebars.js index 7a3025f42e93..dbed1ce8132f 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -42,6 +42,7 @@ module.exports = { 'guides/proxy-management', 'guides/session-management', 'guides/scaling-crawlers', + 'guides/trace-and-monitor-crawlers', 'guides/avoid-blocking', 'guides/cookie-modals', 'guides/jsdom-crawler-guide', diff --git a/website/static/img/jaeger-search.png b/website/static/img/jaeger-search.png new file mode 100644 index 0000000000000000000000000000000000000000..a78636ea84b689554470e9f9d686929d10754cb5 GIT binary patch literal 395443 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�VPyo|#|T2NeB+Qg?Hxn0 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