walkeros-create-cmp-so…
A CMP source is a specialized walkerOS source that listens to a consent management platform's events and translates consent…
The logger is walkerOS's standard logging system, available in all sources and destinations via `env.logger` or `logger` parameter. It provides scoped, level-aware logging that replaces console.log.
$ npx -y skills add elbwalker/walkerOS --skill walkeros-using-logger --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/walkeros-using-loggerContext preview
The summary Claude sees to decide when to auto-load this skill.
The logger is walkerOS's standard logging system, available in all sources and destinations via `env.logger` or `logger` parameter. It provides scoped, level-aware logging that replaces console.log.
name: walkeros-using-logger description: Use when working with walkerOS sources/destinations to understand standard logging patterns, replace console.log, or add logging to external API calls. Covers DRY principles, when to log, and migration patterns.
The logger is walkerOS's standard logging system, available in all sources and destinations via `env.logger` or `logger` parameter. It provides scoped, level-aware logging that replaces console.log.
**Core principle:** Don't log what the collector already logs. Only log meaningful operations like external API calls, transformations, and validation errors.
export const sourceFetch = async (
config: PartialConfig,
env: Types['env'], // env.logger is available here
): Promise<FetchSource> => {
// Logger is scoped automatically by collector: [type:sourceId]
env.logger.info('Server listening on port 3000');
};export const destinationDataManager: DestinationInterface = {
async init({ config, env, logger }) {
// logger parameter is scoped automatically: [datamanager]
logger.debug('Auth client created');
},
async push(event, { config, data, env, logger }) {
// logger parameter is scoped: [datamanager]
logger.debug('API response', { status: 200 });
},
};**Note:** You don't need to create or configure the logger—it's provided automatically with proper scoping.
interface Logger.Instance {
error(message: string | Error, context?: unknown | Error): void;
warn(message: string | Error, context?: unknown | Error): void;
info(message: string | Error, context?: unknown | Error): void;
debug(message: string | Error, context?: unknown | Error): void;
throw(message: string | Error, context?: unknown): never;
json(data: unknown): void;
scope(name: string): Logger.Instance;
}**Default**: ERROR only (must configure to see WARN/INFO/DEBUG)
All methods accept optional structured context:
logger.debug('Sending to API', {
endpoint: '/events',
method: 'POST',
eventCount: 5,
});
// Output: DEBUG [datamanager] Sending to API { endpoint: '/events', method: 'POST', eventCount: 5 }**Why:** Collector can log these automatically since it calls init/push and has scoped logger.
// ✅ GOOD - Fatal configuration error
async init({ config, logger }) {
const { apiKey, projectId } = config.settings || {};
if (!apiKey) {
logger.throw('Config settings apiKey missing');
}
if (!projectId) {
logger.throw('Config settings projectId missing');
}
}**Why logger.throw:**
// ✅ GOOD - Log external calls with context
async push(event, { config, logger }) {
const endpoint = 'https://api.vendor.com/events';
// Log before call
logger.debug('Calling API', {
endpoint,
method: 'POST',
eventId: event.id,
});
const response = await fetch(endpoint, {
method: 'POST',
body: JSON.stringify(event),
});
// Log after call
logger.debug('API response', {
status: response.status,
ok: response.ok,
});
if (!response.ok) {
const errorText = await response.text();
logger.throw(`API error (${response.status}): ${errorText}`);
}
}// ✅ GOOD - Log auth client creation
async init({ config, logger }) {
try {
const authClient = await createAuthClient(config.settings);
logger.debug('Auth client created');
return {
env: { authClient },
};
} catch (error) {
logger.throw(
`Authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
);
}
}// ✅ GOOD - Log server listening (high-level info)
if (settings.port !== undefined) {
server = app.listen(settings.port, () => {
env.logger.info(
`Express source listening on port ${settings.port}\n` +
` POST ${settings.path} - Event collection (JSON body)\n` +
` GET ${settings.path} - Pixel tracking (query params)\n` +
` OPTIONS ${settings.path} - CORS preflight`,
);
});
}async init({ logger }) {
logger.debug('Data Manager init started'); // Redundant
logger.info('Data Manager initializing...'); // Redundant
logger.debug('Settings validated'); // Redundant
const authClient = await createAuthClient();
logger.debug('Auth client created'); // OK
logger.info('Data Manager ready'); // Redundant
}**Problem:** Collector knows when init is called. Only log me
From browser to BigQuery and ad platforms - warehouse-native, and ready for AI agents via MCP.
A CMP source is a specialized walkerOS source that listens to a consent management platform's events and translates consent…
Use when creating a new walkerOS destination to send events to a vendor or API (GA4/gtag, Meta/Facebook Pixel, Mixpanel,…
Use when creating a new walkerOS source to capture events (browser source, dataLayer interception, server/HTTP source, webhook…
| Symptom | Likely Cause | Check | | ---------------------------------- | ---------------------------- |…
Read [understanding-mapping](../walkeros-understanding-mapping/SKILL.md) first for core concepts.