Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/guides/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ are launched in headful mode, i.e. with windows.

Specifies the minimum log level, which can be one of the following values (in order of severity):
`DEBUG`, `INFO`, `WARNING`, `ERROR` and `OFF`. By default, the log level is set to `INFO`,
which means that `DEBUG` messages are not printed to console. See the <ApiLink to="core/class/Log">`utils.log`</ApiLink>
namespace for logging utilities.
which means that `DEBUG` messages are not printed to console. See the [Crawlee logging API](https://github.com/apify/log)
for logging utilities.

#### `CRAWLEE_VERBOSE_LOG`

Expand Down
2 changes: 1 addition & 1 deletion docs/introduction/08-refactoring.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ There's no reason not to split your code into multiple files and keep your logic

## Using Crawlee `log` instead of `console.log`

We won't go to great lengths here to talk about `log` object from Crawlee, because you can read all about it in the <ApiLink to="core/class/Log">documentation</ApiLink>, but there's just one thing that we need to stress: **log levels**.
We won't go to great lengths here to talk about `log` object from Crawlee, because you can read all about it in the [Crawlee logging API](https://github.com/apify/log), but there's just one thing that we need to stress: **log levels**.

Crawlee `log` has multiple log levels, such as `log.debug`, `log.info` or `log.warning`. It not only makes your log more readable, but it also allows selective turning off of some levels by either calling the `log.setLevel()` function or by setting the `CRAWLEE_LOG_LEVEL` environment variable. Thanks to this you can add a lot of debug logs to your crawler without polluting your log when they're not needed, but ready to help when you encounter issues.

Expand Down
420 changes: 420 additions & 0 deletions docs/plans/2026-07-31-001-docs-api-documentation-coverage-plan.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { BrowserPlugin, CommonBrowser, CommonLibrary } from './browser-plug

const PROCESS_KILL_TIMEOUT_MILLIS = 5000;

/** Events emitted by a browser controller. */
export interface BrowserControllerEvents<
Library extends CommonLibrary,
LibraryOptions extends Dictionary | undefined = Parameters<Library['launch']>[0],
Expand Down Expand Up @@ -39,6 +40,7 @@ export abstract class BrowserController<
NewPageOptions = Parameters<LaunchResult['newPage']>[0],
NewPageResult = UnwrapPromise<ReturnType<LaunchResult['newPage']>>,
> extends TypedEmitter<BrowserControllerEvents<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>> {
/** Unique identifier for this browser controller. */
id = nanoid();

/**
Expand Down Expand Up @@ -68,12 +70,16 @@ export abstract class BrowserController<
*/
proxyUrl?: string;

/** Whether the controller has been activated and can open pages. */
isActive = false;

/** Number of pages currently open through this controller. */
activePages = 0;

/** Total number of pages opened by this controller. */
totalPages = 0;

/** Timestamp when the most recent page was opened. */
lastPageOpenedAt = Date.now();

private _activate!: () => void;
Expand Down Expand Up @@ -176,10 +182,12 @@ export abstract class BrowserController<
return page;
}

/** Sets cookies on a browser page. */
async setCookies(page: NewPageResult, cookies: Cookie[]): Promise<void> {
return this._setCookies(page, cookies);
}

/** Reads cookies currently associated with a browser page. */
async getCookies(page: NewPageResult): Promise<Cookie[]> {
return this._getCookies(page);
}
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/autoscaling/autoscaled_pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Snapshotter } from './snapshotter';
import type { SystemInfo, SystemStatusOptions } from './system_status';
import { SystemStatus } from './system_status';

/** Configuration for an {@apilink AutoscaledPool} instance. */
export interface AutoscaledPoolOptions {
/**
* A function that performs an asynchronous resource-intensive task.
Expand Down Expand Up @@ -127,6 +128,7 @@ export interface AutoscaledPoolOptions {
*/
maxTasksPerMinute?: number;

/** Logger used for pool lifecycle and scaling messages. Defaults to Crawlee's global logger. */
log?: Log;
}

Expand Down Expand Up @@ -216,6 +218,7 @@ export class AutoscaledPool {
private tasksDonePerSecondInterval?: BetterIntervalID;
private _tasksPerMinute: number[] = Array.from({ length: 60 }, () => 0);

/** Creates an auto-scaling pool with the supplied task and resource policies. */
constructor(
options: AutoscaledPoolOptions,
private readonly config = Configuration.getGlobalConfig(),
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/autoscaling/client_load_signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@ import { SnapshotStore } from './load_signal';
const CLIENT_RATE_LIMIT_ERROR_RETRY_COUNT = 2;

export interface ClientSnapshot extends LoadSnapshot {
/** Number of storage-client rate-limit errors observed at collection time. */
rateLimitErrorCount: number;
}

export interface ClientLoadSignalOptions {
/** Storage client whose rate-limit statistics should be monitored. */
client: StorageClient;
/** Interval between client snapshots, in seconds. */
clientSnapshotIntervalSecs?: number;
/** Number of new rate-limit errors that marks the client as overloaded. */
maxClientErrors?: number;
/** Fraction of overloaded snapshots required to mark the signal overloaded. */
overloadedRatio?: number;
/** Duration for which snapshots are retained, in milliseconds. */
snapshotHistoryMillis?: number;
}

Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/autoscaling/cpu_load_signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ import { SnapshotStore } from './load_signal';
import type { SystemInfo } from './system_status';

export interface CpuSnapshot extends LoadSnapshot {
/** CPU utilization ratio recorded for the snapshot. */
usedRatio: number;
/** Raw CPU tick counters when collected locally. */
ticks?: { idle: number; total: number };
}

export interface CpuLoadSignalOptions {
/** Fraction of overloaded snapshots required to mark the signal overloaded. */
overloadedRatio?: number;
/** Duration for which snapshots are retained, in milliseconds. */
snapshotHistoryMillis?: number;
/** Crawlee configuration providing the system-info event manager. */
config: Configuration;
}

Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/autoscaling/event_loop_load_signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import type { LoadSnapshot } from './load_signal';
import { SnapshotStore } from './load_signal';

export interface EventLoopSnapshot extends LoadSnapshot {
/** Event-loop delay above the configured threshold, in milliseconds. */
exceededMillis: number;
}

export interface EventLoopLoadSignalOptions {
/** Interval between event-loop measurements, in seconds. */
eventLoopSnapshotIntervalSecs?: number;
/** Delay threshold that marks a measurement as overloaded, in milliseconds. */
maxBlockedMillis?: number;
/** Fraction of overloaded snapshots required to mark the signal overloaded. */
overloadedRatio?: number;
/** Duration for which snapshots are retained, in milliseconds. */
snapshotHistoryMillis?: number;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/autoscaling/load_signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import type { ClientInfo } from './system_status';
* A snapshot of a resource's overload state at a point in time.
*/
export interface LoadSnapshot {
/** Time when the resource measurement was collected. */
createdAt: Date;
/** Whether the resource was overloaded at measurement time. */
isOverloaded: boolean;
}

Expand Down
23 changes: 23 additions & 0 deletions packages/memory-storage/src/memory-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,34 @@ export interface MemoryStorageOptions {
persistStorage?: boolean;
}

/**
* Local storage client that keeps Crawlee data in memory and optionally persists it to disk.
*
* The client implements datasets, key-value stores, and request queues using the configured
* local storage directory.
*/
export class MemoryStorage implements storage.StorageClient {
/** Root directory used for persisted storage data. */
readonly localDataDirectory: string;
/** Directory containing persisted datasets. */
readonly datasetsDirectory: string;
/** Directory containing persisted key-value stores. */
readonly keyValueStoresDirectory: string;
/** Directory containing persisted request queues. */
readonly requestQueuesDirectory: string;
/** Whether metadata sidecar files are written. */
readonly writeMetadata: boolean;
/** Whether storage data is persisted to disk. */
readonly persistStorage: boolean;

/** Key-value store clients created by this storage instance. */
readonly keyValueStoresHandled: KeyValueStoreClient[] = [];
/** Dataset clients created by this storage instance. */
readonly datasetClientsHandled: DatasetClient[] = [];
/** Request queue clients created by this storage instance. */
readonly requestQueuesHandled: RequestQueueClient[] = [];

/** Creates a memory storage client with optional disk persistence. */
constructor(options: MemoryStorageOptions = {}) {
s.object({
localDataDirectory: s.string.optional,
Expand Down Expand Up @@ -83,39 +99,45 @@ export class MemoryStorage implements storage.StorageClient {
: true);
}

/** Returns a client for the datasets collection. */
datasets(): storage.DatasetCollectionClient {
return new DatasetCollectionClient({
baseStorageDirectory: this.datasetsDirectory,
client: this,
});
}

/** Opens a dataset client by identifier. */
dataset<Data extends Dictionary = Dictionary>(id: string): storage.DatasetClient<Data> {
s.string.parse(id);

return new DatasetClient({ id, baseStorageDirectory: this.datasetsDirectory, client: this });
}

/** Returns a client for the key-value stores collection. */
keyValueStores(): storage.KeyValueStoreCollectionClient {
return new KeyValueStoreCollectionClient({
baseStorageDirectory: this.keyValueStoresDirectory,
client: this,
});
}

/** Opens a key-value store client by identifier. */
keyValueStore(id: string): storage.KeyValueStoreClient {
s.string.parse(id);

return new KeyValueStoreClient({ id, baseStorageDirectory: this.keyValueStoresDirectory, client: this });
}

/** Returns a client for the request queues collection. */
requestQueues(): storage.RequestQueueCollectionClient {
return new RequestQueueCollectionClient({
baseStorageDirectory: this.requestQueuesDirectory,
client: this,
});
}

/** Opens a request queue client by identifier. */
requestQueue(id: string, options: storage.RequestQueueOptions = {}): storage.RequestQueueClient {
s.string.parse(id);
s.object({
Expand All @@ -131,6 +153,7 @@ export class MemoryStorage implements storage.StorageClient {
});
}

/** Retained for API compatibility; validates the inputs but performs no operation. */
async setStatusMessage(message: string, options: storage.SetStatusMessageOptions = {}): Promise<void> {
s.string.parse(message);
s.object({
Expand Down
Loading
Loading