> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.itential.com/itential-platform/6/monitor/log/best-practices/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.itential.com/_mcp/server. # Logging best practices > Developer guidelines for secure and effective logging Follow these guidelines when implementing logging in Itential Platform adapters, applications, and integrations. ## Before you begin * Understand log formats and severity levels * Know your Platform version (affects logging signature requirements) * Review your organization's data security policies ## Itential's logging security policy Itential Platform automatically excludes Authentication, Authorization, and Accounting (AAA) sensitive data from logs, including Platform passwords, API keys, tokens, and credentials. **However, Itential does not modify third-party system payloads.** ### Third-party payload data Platform does not filter data from external systems: * API responses from external systems (ServiceNow, Ansible, Splunk) * Device configurations from network equipment (Cisco, Juniper, Arista) * Authentication tokens from external auth providers (Okta, Active Directory) * Data returned from monitoring tools, ticketing systems, and cloud providers ### Your responsibility **You must filter sensitive data from third-party payloads before logging.** Implement appropriate filtering in your workflows and custom code according to your organization's security policies. Always create context objects containing only known-safe fields. Never log entire objects that may contain sensitive data. ## Use structured logging **Requirements:** Platform 2023.2 or 6.2+ Use the structured logging signature with a single object containing `message`, `context`, and `error` fields. **Do this:** ```javascript log.info({ message: 'User authentication successful', context: { userId: user.id, username: user.username, method: 'ldap' } }); ``` **Not this:** ```javascript // Multi-argument format (legacy) log.info('User authentication successful', user); ``` Structured logging enables automated parsing and prevents accidental exposure of sensitive data. ### Migrate to structured logging **Requirements:** Platform 2023.2 or 6.2+ Update existing multi-argument log calls to structured logging format. **Before migration:** ```javascript log.warn('Service connection timed out', 'service-A', 5000); ``` **After migration:** ```javascript log.warn({ message: 'Service connection timed out', context: { serviceName: 'service-A', timeoutMs: 5000 }, error: err }); ``` **Migration steps:** ### Set logger version Set `loggerVersion` to `2` in your application's **pronghorn.json** file. ### Identify primary message Find the main message (typically first argument). ### Create context object Create `context` object with named fields for additional data. ### Verify no sensitive data Ensure context contains only known-safe fields. ### Add error object Include `error` object for error and warn levels. ## Choose the correct log level Select appropriate severity level based on event type and required response. | Level | When to use | Example | | -------- | --------------------------------------------------- | ------------------------------------------------------------ | | `system` | Critical platform lifecycle events only | Platform initialization complete, shutting down | | `error` | Unrecoverable errors requiring immediate attention | Database connection lost, authentication service unavailable | | `warn` | Recoverable issues requiring monitoring | API retry in progress, deprecated feature used | | `info` | Normal operational messages | User logged in, workflow completed, service started | | `debug` | Detailed diagnostic information for troubleshooting | Configuration loaded, API response received | | `trace` | Step-by-step execution flow | Function entry/exit, variable values | | `spam` | Extremely frequent events | Loop iterations, polling events | ### Best practices for log levels * Use `info` for events you'd want in production dashboards * Use `debug` only during active troubleshooting * Reserve `error` for situations requiring human intervention * Always include `error` objects with `error` and `warn` levels * Never use `trace` or `spam` in production ## Write clear messages Write log messages that explain what happened and provide troubleshooting context. **Do this:** ```javascript log.error({ message: 'Failed to update user profile in database', context: { userId: 'user123', operation: 'updateEmail' }, error: err }); ``` **Not this:** ```javascript log.error({ message: 'Update failed', error: err }); ``` ### Message guidelines * State what operation was attempted * Include relevant identifiers (user ID, resource ID) * Explain the outcome (success, failure, retry) * Provide context for troubleshooting * Avoid generic messages like "Error occurred" or "Processing complete" ## Filter sensitive data Always create context objects containing only known-safe fields. ### Create safe context objects Extract only the fields you need and explicitly define them. **Do this:** ```javascript const logContext = { userId: user.id, username: user.username, operation: 'updateProfile' }; log.info({ message: 'User profile updated successfully', context: logContext }); ``` **Not this:** ```javascript // Entire user object may contain email, address, or other PII log.info({ message: 'User profile updated successfully', context: user // NEVER DO THIS }); ``` ### Filter third-party payloads Extract only metadata from third-party responses. Never log full response bodies. **Do this:** ```javascript log.debug({ message: 'ServiceNow API response received', context: { endpoint: '/api/now/table/incident', statusCode: response.status, recordCount: response.data.result.length } }); ``` **Not this:** ```javascript // response.data may contain PII or sensitive content log.debug({ message: 'ServiceNow API response received', context: { endpoint: '/api/now/table/incident', responseData: response.data // NEVER DO THIS } }); ``` ### Sensitive data categories **Platform data (handled by Itential):** * Platform passwords, API keys, tokens, secrets * Platform authorization headers, cookies, sessions * Platform JWT tokens, OAuth credentials **Third-party data (your responsibility):** * API response payloads from external systems * Device configurations from network equipment * Credentials or tokens in third-party responses * Customer data from external integrations **Personally Identifiable Information:** * Email addresses, phone numbers, full names * Social security numbers, addresses * IP addresses (context-dependent) **Business & customer data:** * Customer-specific business data * Proprietary configurations * Sensitive content from third-party systems ## Log useful context Include relevant context that helps diagnose issues without exposing sensitive data. ### API calls Log metadata about API requests and responses: ```javascript log.info({ message: 'Outbound API request', context: { service: 'ServiceNow', endpoint: '/api/now/table/incident', method: 'POST', correlationId: req.headers['x-correlation-id'] } }); ``` **Include:** * HTTP method, endpoint (without sensitive query parameters) * Status codes, response times * Correlation IDs, operation names * Record counts **Exclude:** * Request/response bodies * Authorization headers * API keys in URLs * Full third-party payloads ### Database operations Log query metadata and execution details: ```javascript log.debug({ message: 'Database query executed', context: { collection: 'users', operation: 'findOne', query: { _id: userId }, resultFound: !!result, duration: queryDuration } }); ``` **Include:** * Collection/table name * Operation type * Query parameters (if not sensitive) * Success/failure status * Execution time **Exclude:** * Full result sets * Connection strings with credentials * Entire documents with PII ### Workflows Log workflow execution details: ```javascript log.info({ message: 'Workflow execution started', context: { workflowName: 'deploy_configuration', workflowId: workflow.id, triggeredBy: user.username, targetDevices: deviceCount } }); ``` **Include:** * Workflow name and ID * Initiating user (username only) * Count of affected resources * Execution stage **Exclude:** * Complete workflow payloads * Device configurations * Credential data * Full third-party responses ### Authentication Log authentication events for security auditing: ```javascript log.info({ message: 'User authentication successful', context: { userId: user.id, username: user.username, authMethod: 'ldap', sourceIp: req.ip } }); ``` **Include:** * User identifier * Authentication method * Success/failure status * Source IP (if relevant) **Exclude:** * Passwords, credentials * Full authentication payloads * Session tokens ### Third-party integrations Log integration operation metadata: ```javascript log.debug({ message: 'Device configuration retrieved', context: { deviceId: device.id, deviceType: device.type, configSize: config.length, retrievalTime: duration } }); ``` **Include:** * Metadata about the operation * Device ID, data size, timing * Success/failure **Exclude:** * Full configurations * Credentials * Proprietary settings * Customer data ## Handle errors Always include error objects with `error` and `warn` level logs. ```javascript try { await database.updateUser(userId, updates); } catch (err) { log.error({ message: 'Failed to update user in database', context: { userId: userId, operation: 'updateUser', attemptedUpdates: Object.keys(updates) }, error: err }); throw err; } ``` ### Error handling best practices * Explain what the code was trying to do when it failed * Include relevant identifiers (user ID, resource ID) * Include the error object for stack traces * Don't log the same error multiple times as it propagates * Use appropriate log level (error vs warn) ## Use appropriate log frequency Log summaries of batch operations rather than individual iterations. **Do this:** ```javascript log.info({ message: 'Processed device configurations', context: { deviceCount: devices.length, successCount: results.filter(r => r.success).length, failureCount: results.filter(r => !r.success).length, duration: processingTime } }); ``` **Not this:** ```javascript devices.forEach(device => { log.debug({ message: 'Processing device', context: { deviceId: device.id } }); processDevice(device); }); ``` ### Frequency best practices * Log summaries of batch operations, not individual iterations * Use `trace` or `spam` for high-frequency events during development * Remove or reduce verbosity in production code * Consider performance impact of excessive logging ## Common logging patterns ### Successful operation ```javascript log.info({ message: 'Configuration deployed successfully', context: { workflowId: workflow.id, deviceCount: 5, duration: executionTime } }); ``` ### Recoverable warning ```javascript log.warn({ message: 'API request retry scheduled after timeout', context: { service: 'ServiceNow', endpoint: '/api/now/table/incident', retryAttempt: 2, maxRetries: 3, retryDelay: 5000 }, error: timeoutError }); ``` ### Unrecoverable error ```javascript log.error({ message: 'Database connection pool exhausted', context: { poolSize: config.db.poolSize, activeConnections: pool.activeCount, waitingRequests: pool.waitingCount }, error: poolError }); ``` ### Debug information ```javascript log.debug({ message: 'External API response received', context: { service: 'ServiceNow', endpoint: '/api/now/table/incident', statusCode: response.status, responseTime: responseTime, recordCount: response.data.result.length } }); ``` ### Third-party payload filtering **Do this - Log metadata only:** ```javascript log.debug({ message: 'Network device configuration backup completed', context: { deviceId: device.id, deviceType: 'cisco_ios', configLines: configData.split('\n').length, backupSize: Buffer.byteLength(configData), duration: backupTime } }); ``` **Not this - Logging full configuration:** ```javascript log.debug({ message: 'Network device configuration backup completed', context: { deviceId: device.id, configData: configData // MAY CONTAIN PASSWORDS AND SENSITIVE SETTINGS } }); ``` ## Automated validation **Requirements:** Platform 2023.2 or 6.2+ Platform automatically validates logging code during development. **Validation checks:** * All log calls pass a single object as argument * Object contains a `message` property * `context` property (if present) is an object * `log.error` and `log.warn` calls include an `error` property Code violating these rules triggers ESLint warnings. **Valid:** ```javascript log.info({ message: 'Operation completed' }); log.error({ message: 'Operation failed', context: { userId: '123' }, error: err }); ``` **Invalid:** ```javascript log.info('Operation completed'); // Not an object log.error({ message: 'Failed' }); // Missing error property log.info({ context: { userId: '123' }}); // Missing message ``` ## Multi-argument logging (Platform 2023.1 and earlier) For Platform versions before 2023.2, use multi-argument logging signature. Pass only safe, specific values as arguments: ```javascript log.info('User authentication successful', userId, authMethod); ``` **Never pass entire objects:** ```javascript // Don't pass entire objects - may contain sensitive data log.info('User authenticated', user); // WRONG log.debug('Request received', req); // WRONG log.debug('API response', apiResponse); // WRONG ``` ### Legacy logging best practices * Only pass specific, known-safe values as arguments * Avoid passing request, response, user, or configuration objects * Manually extract safe fields before logging * Filter third-party payloads before logging any data ## Performance considerations ### Logging overhead * Console logging has higher performance impact than file logging * Structured JSON logging is more efficient than standard format * Excessive logging in hot paths impacts performance * Log level affects volume and performance ### Production recommendations * Use `info` or `warn` log level * Disable `debug` logging * Never use `trace` or `spam` * Log summaries of batch operations * Monitor log volume and performance impact ## Next steps #### [Logging overview](/itential-platform/monitor/log/overview) Understand log formats and levels #### [Configure logging](/itential-platform/monitor/log/configure) Set log levels and rotation settings #### [View and search logs](/itential-platform/monitor/log/view-and-search) Access and search log files #### [Troubleshoot logging](/itential-platform/monitor/log/troubleshoot) Resolve common logging issues > Developer guidelines for secure and effective logging