Attributes
Attributes are key-value pairs that add structured data to log records.
What are Attributes?
Attributes provide context to log messages in a structured, machine-parseable format:
import { info, String, Int, Bool } from '@omdxp/jslog';
info('User action',
String('user', 'alice'), // String attribute
String('action', 'login'), // String attribute
Int('attempts', 3), // Integer attribute
Bool('success', true) // Boolean attribute
);
Attribute Types
String
String values:
import { String } from '@omdxp/jslog';
logger.info('Event', String('name', 'user.created'));
Int / Int64
Integer values:
import { Int, Int64 } from '@omdxp/jslog';
logger.info('Metrics',
Int('count', 42),
Int64('user_id', 9007199254740991)
);
Uint64
Unsigned 64-bit integer:
import { Uint64 } from '@omdxp/jslog';
logger.info('ID', Uint64('transaction_id', 12345678901234567));
Float64
Floating point numbers:
import { Float64 } from '@omdxp/jslog';
logger.info('Metrics',
Float64('cpu_usage', 85.5),
Float64('memory_mb', 1024.75)
);
Bool
Boolean values:
import { Bool } from '@omdxp/jslog';
logger.info('Status',
Bool('is_active', true),
Bool('has_premium', false)
);
Time
Date/time values:
import { Time } from '@omdxp/jslog';
logger.info('Event',
Time('created_at', new Date()),
Time('scheduled_for', new Date('2024-12-31'))
);
Duration
Duration in milliseconds:
import { Duration } from '@omdxp/jslog';
logger.info('Performance',
Duration('elapsed', 1500) // Outputs as "1500ms"
);
Any
Any value (objects, arrays, etc.):
import { Any } from '@omdxp/jslog';
logger.info('Complex data',
Any('config', { timeout: 5000, retries: 3 }),
Any('tags', ['production', 'api'])
);
Group
Group related attributes:
import { Group, String, Int } from '@omdxp/jslog';
logger.info('User event',
Group('user',
String('id', 'u123'),
String('email', 'alice@example.com')
),
Group('location',
String('city', 'NYC'),
String('country', 'USA')
)
);
// JSON Output:
// {
// "user": { "id": "u123", "email": "alice@example.com" },
// "location": { "city": "NYC", "country": "USA" }
// }
Err
Error objects with stack traces:
import { Err } from '@omdxp/jslog';
try {
throw new Error('Connection timeout');
} catch (err) {
logger.error('Operation failed', Err(err as Error));
}
// Can also use with error messages
logger.error('Failed', Err('Custom error message'));
Advanced Attribute Usage
Nested Groups
import { Group, String, Int } from '@omdxp/jslog';
logger.info('Server config',
Group('server',
Int('port', 8080),
Group('database',
String('host', 'localhost'),
Int('pool_size', 10)
)
)
);
// Output: server.port=8080 server.database.host="localhost" server.database.pool_size=10
Using with Logger Context
import { New, TextHandler, String, Int } from '@omdxp/jslog';
const baseLogger = New(new TextHandler());
// Add persistent attributes
const appLogger = baseLogger.with(
String('app', 'myapp'),
String('version', '1.0.0')
);
// All logs from appLogger include these attributes
appLogger.info('Started', Int('port', 3000));
// Output includes: app="myapp" version="1.0.0" port=3000
AttrBuilder (Fluent API)
Build attributes fluently:
import { attrs } from '@omdxp/jslog';
const attributes = attrs()
.str('user', 'alice')
.num('age', 30)
.bool('active', true)
.time('created', new Date())
.if(condition, 'conditional', 'value') // Only add if condition is true
.from({ role: 'admin', team: 'engineering' }) // Add from object
.build();
logger.info('User created', ...attributes);
Generic Attribute Constructor
Create attributes manually:
import { attr } from '@omdxp/jslog';
const customAttr = attr('custom_key', 'custom_value');
logger.info('Message', customAttr);
LogValuer Interface
Create custom types that control how they're logged:
import { LogValuer, Value } from '@omdxp/jslog';
class User implements LogValuer {
constructor(
public id: string,
public email: string,
private password: string // Sensitive!
) {}
logValue(): Value {
// Only expose safe data
return {
id: this.id,
email: this.maskEmail(this.email)
};
}
private maskEmail(email: string): string {
const [name, domain] = email.split('@');
return `${name[0]}***@${domain}`;
}
}
const user = new User('u123', 'alice@example.com', 'secret');
logger.info('User action', Any('user', user));
// Logs: user={"id":"u123","email":"a***@example.com"}
Best Practices
1. Use Appropriate Types
// ❌ Bad: Everything as strings
logger.info('Stats', String('count', '42'), String('active', 'true'));
// ✅ Good: Use proper types
logger.info('Stats', Int('count', 42), Bool('active', true));
2. Group Related Data
// ❌ Bad: Flat structure
logger.info('Event',
String('user_id', '123'),
String('user_email', 'alice@example.com'),
String('user_role', 'admin')
);
// ✅ Good: Grouped
logger.info('Event',
Group('user',
String('id', '123'),
String('email', 'alice@example.com'),
String('role', 'admin')
)
);
3. Consistent Naming
// ✅ Good: Consistent snake_case
logger.info('Event',
String('user_id', '123'),
String('request_id', 'req-456'),
Int('response_time_ms', 150)
);
4. Avoid Sensitive Data
// ❌ Bad: Logging sensitive data
logger.info('Login', String('password', password));
// ✅ Good: Redact or omit
logger.info('Login', String('user', username)); // No password!