Skip to content

docs: add custom logger guide#3470

Open
pangerlkr wants to merge 9 commits intoapify:v4from
pangerlkr:docs/custom-logger
Open

docs: add custom logger guide#3470
pangerlkr wants to merge 9 commits intoapify:v4from
pangerlkr:docs/custom-logger

Conversation

@pangerlkr
Copy link

@pangerlkr pangerlkr commented Mar 9, 2026

Closes #3460

What this PR adds

Adds a new guide to the v4 docs: "Using a custom logger".

This is a follow-up to #3399 which introduced the CrawleeLogger interface and
BaseCrawleeLogger abstract class.

Files added

  • website/versioned_docs/version-4.0/guides/custom-logger/custom-logger.mdx — the guide page
  • website/versioned_docs/version-4.0/guides/custom-logger/implementation.ts — Winston adapter implementation example
  • website/versioned_docs/version-4.0/guides/custom-logger/usage.ts — crawler usage example
  • website/versioned_sidebars/version-4.0-sidebars.json — registers the new guide in the sidebar

Guide covers

  • When and why to use a custom logger (centralized logs, Datadog/ELK/CloudWatch, JSON format)
  • The CrawleeLogger interface and the two methods to implement (logWithLevel + createChild)
  • Full Winston adapter example with level mapping
  • How to wire the adapter to a crawler via serviceLocator.setLogger()
  • How to use a different logging library (Pino, Bunyan, etc.)
  • How log level control works with custom loggers

Copilot AI review requested due to automatic review settings March 9, 2026 05:48
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “Using a custom logger” guide intended for the v4 documentation, including a Winston adapter example and a usage snippet, and registers the page in the v4 sidebar.

Changes:

  • Adds a new MDX guide page for custom logger usage.
  • Adds TypeScript example files (Winston adapter implementation + crawler usage).
  • Adds a versioned sidebar entry for the new guide.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
website/versioned_docs/version-4.0/guides/custom-logger/custom-logger.mdx New guide explaining the custom logger concept and showing examples.
website/versioned_docs/version-4.0/guides/custom-logger/implementation.ts Winston adapter implementation example to embed in the docs.
website/versioned_docs/version-4.0/guides/custom-logger/usage.ts Example showing how to wire the adapter into a crawler.
website/versioned_sidebars/version-4.0-sidebars.json Registers the new guide in the v4 sidebar.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +2 to +4
import { BaseCrawleeLogger } from 'crawlee';
import type { CrawleeLogger, CrawleeLoggerOptions } from 'crawlee';

Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BaseCrawleeLogger, CrawleeLogger, and CrawleeLoggerOptions are imported from crawlee here, but they are not present in this repository’s source exports (full-repo search finds no definitions). That makes this example unusable as a copy/paste snippet; either adjust the imports/types to match the actual public API, or add the missing logger abstraction implementation to the codebase.

Suggested change
import { BaseCrawleeLogger } from 'crawlee';
import type { CrawleeLogger, CrawleeLoggerOptions } from 'crawlee';
// Minimal local definitions mirroring Crawlee's logger abstraction,
// so this example is self-contained and does not rely on unexported symbols.
export interface CrawleeLoggerOptions {
prefix?: string;
}
export abstract class BaseCrawleeLogger {
private readonly options: CrawleeLoggerOptions;
protected constructor(options?: Partial<CrawleeLoggerOptions>) {
this.options = { ...options };
}
protected getOptions(): CrawleeLoggerOptions {
return this.options;
}
protected abstract log(level: number, message: string, data?: Record<string, unknown>): void;
protected abstract _createChild(options: Partial<CrawleeLoggerOptions>): CrawleeLogger;
child(options: Partial<CrawleeLoggerOptions>): CrawleeLogger {
return this._createChild(options);
}
}
export type CrawleeLogger = BaseCrawleeLogger;

Copilot uses AI. Check for mistakes.

// Wrap your Winston logger in the adapter and pass it to Configuration
const config = new Configuration({
loggerProvider: new WinstonAdapter(winstonLogger),
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loggerProvider is not a recognized Configuration option in this repo (see packages/core/src/configuration.ts), so this usage snippet won’t compile/work for users. Please update to the real configuration/injection API for custom loggers, or add the corresponding ConfigurationOptions support if that’s the intended public interface.

Suggested change
loggerProvider: new WinstonAdapter(winstonLogger),
logger: new WinstonAdapter(winstonLogger),

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +5
{
"docs": [
"quick-start/quick-start",
{
"type": "category",
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds a version-4.0-sidebars.json, but website/versions.json does not list 4.0, so the new guide won’t show up in any rendered docs version. If the intent is to document the unreleased/next docs, this should be added to docs/ + website/sidebars.js; if the intent is a new released docs version, you’ll also need to version the full docs set and register 4.0 in versions.json (otherwise this sidebar will reference many non-existent doc IDs under versioned_docs/version-4.0).

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +60
## The `CrawleeLogger` interface

Crawlee expects a logger that satisfies the `CrawleeLogger` interface. The easiest way to
build one is to extend the `BaseCrawleeLogger` abstract class and implement two methods:

- **`log(level, message, data?)`** — the core dispatch method called for every log entry.
- **`_createChild(options)`** — returns a new logger instance scoped to a prefix (e.g. the crawler name).

All other methods (`info`, `debug`, `warning`, `error`, `warningOnce`, etc.) are provided
for free by `BaseCrawleeLogger`.

## Example: Winston adapter

The following adapter wraps a standard Winston logger:

<CodeBlock language="ts">{ImplementationSource}</CodeBlock>

### Wiring the adapter into a crawler

Pass a new instance of your adapter to `Configuration` via the `loggerProvider` option,
then hand that `Configuration` object to your crawler:

<CodeBlock language="ts">{UsageSource}</CodeBlock>

The `log` object available inside `requestHandler` is a child logger scoped to the
crawler, so prefix-tagged entries like `[CheerioCrawler] Processing ...` appear in your
Winston output automatically.

## Using a different logging library

The same pattern works for any library. Create a class that extends `BaseCrawleeLogger`,
map the numeric `level` argument (0 = error, 1 = warning, 3 = info, 5 = debug) to your
library's level constants inside `log()`, and delegate child-logger creation in
`_createChild()`. You only need those two methods — everything else is handled for you.

## Controlling log level

When using the default `@apify/log`, the `logLevel` option in `Configuration` (or the
`CRAWLEE_LOG_LEVEL` environment variable) controls verbosity. When you supply your own
logger via `loggerProvider`, Crawlee delegates level filtering entirely to your logger,
so configure it there.
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guide references CrawleeLogger / BaseCrawleeLogger, but those symbols don’t exist anywhere in this repo’s crawlee exports (a full-repo search for CrawleeLogger/BaseCrawleeLogger returns no matches). As-is, users won’t be able to follow these instructions; either update the guide to match the actual public logging API in this codebase (currently log in crawling contexts is @apify/log’s Log), or include the missing logger-abstraction implementation in the PR.

Suggested change
## The `CrawleeLogger` interface
Crawlee expects a logger that satisfies the `CrawleeLogger` interface. The easiest way to
build one is to extend the `BaseCrawleeLogger` abstract class and implement two methods:
- **`log(level, message, data?)`** — the core dispatch method called for every log entry.
- **`_createChild(options)`** — returns a new logger instance scoped to a prefix (e.g. the crawler name).
All other methods (`info`, `debug`, `warning`, `error`, `warningOnce`, etc.) are provided
for free by `BaseCrawleeLogger`.
## Example: Winston adapter
The following adapter wraps a standard Winston logger:
<CodeBlock language="ts">{ImplementationSource}</CodeBlock>
### Wiring the adapter into a crawler
Pass a new instance of your adapter to `Configuration` via the `loggerProvider` option,
then hand that `Configuration` object to your crawler:
<CodeBlock language="ts">{UsageSource}</CodeBlock>
The `log` object available inside `requestHandler` is a child logger scoped to the
crawler, so prefix-tagged entries like `[CheerioCrawler] Processing ...` appear in your
Winston output automatically.
## Using a different logging library
The same pattern works for any library. Create a class that extends `BaseCrawleeLogger`,
map the numeric `level` argument (0 = error, 1 = warning, 3 = info, 5 = debug) to your
library's level constants inside `log()`, and delegate child-logger creation in
`_createChild()`. You only need those two methods — everything else is handled for you.
## Controlling log level
When using the default `@apify/log`, the `logLevel` option in `Configuration` (or the
`CRAWLEE_LOG_LEVEL` environment variable) controls verbosity. When you supply your own
logger via `loggerProvider`, Crawlee delegates level filtering entirely to your logger,
so configure it there.
## Crawlee's logging API
Crawlee uses [`@apify/log`](https://github.com/apify/apify-js/tree/master/packages/log) internally.
In crawling contexts (for example, inside `requestHandler`), the `log` object you receive is
an instance of `@apify/log`’s `Log` class.
This logger exposes familiar methods such as `info`, `debug`, `warning`, `error`,
`exception`, and `warningOnce`, as well as a generic `log(level, message, data?)` method.
You can use it directly, or wrap/forward its calls into another logging system (e.g. Winston,
Pino, or your centralized logging pipeline).
## Example: Winston adapter
The following adapter shows one way to integrate Crawlee’s logging with a standard Winston logger:
<CodeBlock language="ts">{ImplementationSource}</CodeBlock>
### Wiring the adapter into a crawler
Use the adapter inside your crawler code (for example, in `requestHandler`) to forward
messages from Crawlee’s `log` (or from your own code) into Winston:
<CodeBlock language="ts">{UsageSource}</CodeBlock>
In crawling contexts, the `log` object made available by Crawlee is already scoped to the
crawler (for example, it may prefix entries with `[CheerioCrawler]`), so those tags will
appear automatically in your Winston output when you forward messages through the adapter.
## Using a different logging library
The same pattern works for any library. Create a small adapter that accepts Crawlee’s
log calls (or an `@apify/log` `Log` instance), map the numeric log `level` values
(0 = error, 1 = warning, 3 = info, 5 = debug) to your library’s levels, and delegate
to your library’s logging methods. You typically only need to handle the level mapping
and any additional metadata/formatting your logger expects.
## Controlling log level
When using the default `@apify/log`, you can control verbosity with the
`CRAWLEE_LOG_LEVEL` environment variable (or by configuring `@apify/log` directly in
your application). If you also use an external logger (such as Winston), configure that
logger’s own level filtering and formatting according to its documentation.

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +42
### Wiring the adapter into a crawler

Pass a new instance of your adapter to `Configuration` via the `loggerProvider` option,
then hand that `Configuration` object to your crawler:

<CodeBlock language="ts">{UsageSource}</CodeBlock>
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configuration({ loggerProvider }) is not a valid API in this repo: ConfigurationOptions (packages/core/src/configuration.ts) has no loggerProvider field, so this wiring example won’t typecheck/work. Please update the docs to the actual injection point used by the logger abstraction, or adjust the code changes so that Configuration accepts a custom logger provider as documented.

Copilot uses AI. Check for mistakes.
@janbuchar janbuchar requested a review from l2ysho March 9, 2026 12:56
Copy link
Contributor

@l2ysho l2ysho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for contribution @pangerlkr . Pls make sure that lint and test are 🟢. Also there are some comments by copilot, at least this and this looks relevant to me.

@pangerlkr
Copy link
Author

@l2ysho , thanks for pointing out; I've fixed the issue.
The CI checks should now pass once the pipeline re-runs on the updated branch.

@l2ysho
Copy link
Contributor

l2ysho commented Mar 12, 2026

@pangerlkr #3470 (comment) this is a definitely an issue, pls check also other Copilot comments and make sure your fork is up to date. Configuration({ loggerProvider }) this is something which is not part of v4 branch anymore.

@pangerlkr
Copy link
Author

@l2ysho All Copilot comments and the Configuration({ loggerProvider }) issue have been addressed. Here's a summary of changes made:

implementation.ts: Renamed abstract method log()logWithLevel() and _createChild()createChild() to match the actual BaseCrawleeLogger API in v4. Also corrected the LogLevel numeric mapping (ERROR=1, SOFT_FAIL=2, WARNING=3, INFO=4, PERF=5, DEBUG=6).

usage.ts: Replaced the non-existent Configuration({ loggerProvider }) pattern with the correct serviceLocator.setLogger() API.

custom-logger.mdx: Updated all method name references (logWithLevel, createChild), the wiring section (now uses serviceLocator.setLogger()), and the log level section to accurately describe how level filtering works.

Regarding the Copilot comment about versions.json"4.0" is already present in versions.json on the v4 branch (added via #3292), and versioned_docs/version-4.0 already exists, so that concern is no longer applicable.

The CI workflow is still awaiting maintainer approval to run the full test suite.

@pangerlkr pangerlkr requested a review from l2ysho March 14, 2026 05:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants