Fields¶
For extra context, every log is accompanied with an optional fields dictionary.
It's encouraged to put changing parts of your log messages inside of fields argument as it makes it simpler to match on such attributes
while creating workflows. For example, instead of logging message "Timezone changed from X to Y" log "Timezone changed" message with
fields two fields: from and to.
Logger.log(LogLevel.INFO, mapOf("from" to "UTC", "to" to "PST")) { "Timezone changed" }
HashMap fields = new HashMap();
fields.put("from", "UTC");
fields.put("to", "PST");
Logger.log(LogLevel.INFO, fields, () -> "Timezone changed");
Logger.log(level: .info, "Timezone changed", fields: ["from": "UTC", "to": "PST"])
[CAPLogger logWithLevel:LogLevel.info message:@"Timezone changed" fields: @{@"from": @"UTC", @"to": @"PST"}];
import { info } from '@bitdrift/react-native';
info('Timezone changed', { from: 'UTC', to: "PST" });
import { info } from '@bitdrift/react-native';
info('Timezone changed', { from: 'UTC', to: "PST" });
There are three different ways to attach fields to logs. Below is the list, in order of priority, indicating which methods have precedence over others (fields provided by methods higher in the list override those provided by methods lower in the list):
- Using the
fieldsargument in a specificlog(...)method: This gives the greatest level of control on a per-log basis but has the highest performance impact. Refer to Custom Fields for more details. - Using the
addField(...)method: This attaches fields to all logs emitted by the SDK after the method call. It is the most performant way to add fields to logs. Refer toField Addition and Removal Methods for more details. - Implementing
FieldsProviderprotocol/interface: This approach is more flexible but less direct. Refer to Field Providers for more details.
Default Fields¶
Every log emitted by the SDK is tagged with extra out-of-the-box attributes related to the device and app state. Below is the their list:
| Field Name | Field Key | Notes |
|---|---|---|
| App Identifier | app_id |
|
| App Version | app_version |
The value of the versionName attribute of the PackageInfo |
| App Version Code | _app_version_code |
The value obtained using getLongVersionCode or versionCode accessors. |
| Carrier | carrier |
|
| Foreground | foreground |
|
| Locale | _locale |
The string value of the getLocales method call. |
| Log Level | level |
|
| Network Type | network_type |
|
| Network Quality | _network_quality |
Expose if the app is Offline based on its ability to reach the bitdrift ingest API. The field is not shown if the app is online. Note that any successful network request will identify the app as online |
| OS | os |
|
| OS Version | os_version |
The value of RELEASE property. |
| Radio Type | radio_type |
| Field Name | Field Key | |
|---|---|---|
| App Identifier | app_id |
|
| App Version | app_version |
The value stored under the CFBundleShortVersionString key of the info dictionary of the main Bundle. |
| Build Number | _build_number |
The valued stored under the kCFBundleVersionKey key of the infoDictionary property of the main Bundle. |
| Foreground | foreground |
|
| Locale | _locale |
The value of the Locale.current.identifier property. |
| Log Level | level |
|
| Network Type | network_type |
|
| Network Quality | _network_quality |
Expose if the app is Offline based on its ability to reach the bitdrift ingest API. The field is not shown if the app is online. Note that any successful network request will identify the app as online |
| OS | os |
|
| OS Version | os_version |
The value of systemVersion property. |
| Radio Type | radio_type |
React Native supports all the out of the box fields provided by the platform the app is running on, see the iOS and Android sections for more details.
Custom Fields¶
The SDK allows all but the following field names to be used by the customers of the SDK:
- Fields with keys that conflict with keys of the default fields emitted by the SDK. This is enforced for all fields and offending fields are dropped (a warning message is printed in the console when that happens).
- Fields whose names start with "_" (underscore character). This is enforced for global fields
and offending fields are dropped (a warning message is printed in the console when that happens). The rule is going to be
enforced for
fieldsarguments of custom logs in the future.
Providing Fields with Logging Methods¶
You can attach arbitrary fields to logs emitted by and with the use of the SDK.
Logger.log(LogLevel.INFO, mapOf("key" to "value")) { "Info log" }
Logger.logTrace(mapOf("key" to "value")) { "Trace log" }
Logger.logDebug(mapOf("key" to "value")) { "Debug log" }
Logger.logInfo(mapOf("key" to "value")) { "Info log" }
Logger.logWarning(mapOf("key" to "value")) { "Warning log" }
Logger.logError(mapOf("key" to "value")) { "Error log" }
Logger.log(LogLevel.INFO, Collections.singletonMap("key", "value"), () -> "Info log");
Logger.logTrace(Collections.singletonMap("key", "value"), () -> "Trace log");
Logger.logDebug(Collections.singletonMap("key", "value"), () -> "Debug log");
Logger.logInfo(Collections.singletonMap("key", "value"), () -> "Info log");
Logger.logWarning(Collections.singletonMap("key", "value"), () -> "Warning log");
Logger.logError(Collections.singletonMap("key", "value"), () -> "Error log");
Logger.log(level: .info, "Info log", fields: ["key": "value"])
Logger.logTrace("Trace log", fields: ["key": "value"])
Logger.logDebug("Debug log", fields: ["key": "value"])
Logger.logInfo("Info log", fields: ["key": "value"])
Logger.logWarning("Warning log", fields: ["key": "value"])
Logger.logError("Error log", fields: ["key": "value"])
[CAPLogger logWithLevel:LogLevel.info message:@"Info log" fields: @{@"key": @"value"}];
[CAPLogger logTrace:@"Trace log" fields:@{@"key": @"value"}];
[CAPLogger logDebug:@"Debug log" fields:@{@"key": @"value"}];
[CAPLogger logInfo:@"Info log" fields:@{@"key": @"value"}];
[CAPLogger logWarning:@"Warning log" fields:@{@"key": @"value"}];
[CAPLogger logError:@"Error log" fields:@{@"key": @"value"}];
import { info } from '@bitdrift/react-native';
// Log line with LogLevel of Trace
trace('Hello world!', { key: 'value' });
debug('Hello world!', { key: 'value' });
info('Hello world!', { key: 'value' });
warning('Hello world!', { key: 'value' });
error('Hello world!', { key: 'value' });
import { info } from '@bitdrift/react-native';
// Log line with LogLevel of Trace
trace('Hello world!', { key: 'value' });
debug('Hello world!', { key: 'value' });
info('Hello world!', { key: 'value' });
warning('Hello world!', { key: 'value' });
error('Hello world!', { key: 'value' });
Global Fields¶
The SDK supports two ways of adding log fields to attach to every emitted log. Each of these methods manages a separate pool of logs, ensuring that the method of managing fields does not impact those managed by the other method.
Note
Global fields are not persisted to disk and thus do not survive process restarts, so it is possible for these values to change within a session depending on your session management strategy.
Field Addition and Removal Methods¶
The logger exposes addField(...) and removeField(...) methods, which can be used to control the list of
global fields added to emitted logs.
Logger.addField("key", "value")
Logger.removeField("key")
Logger.addField("key", "value");
Logger.removeField("key");
Logger.addField(withKey: "key", value: "value")
Logger.removeField(withKey: "key")
import { addField, removeField } from '@bitdrift/react-native';
addField('key', 'value');
removeField('key');
Field Providers¶
The start method takes an optional list of fieldProviders where you can implement your own logic for retrieving the data you want to pass.
In cases of key conflicts (where two or more fields share the same key), the earlier a field provider appears in the list of registered providers, the higher priority the field it returns is given.
// Attach your own custom user_id field to each log
class CustomUserIdProvider : FieldProvider {
override fun invoke(): Fields {
return mapOf("user_id" to "<your_custom_user_id>")
}
}
Logger.start(
// ...
fieldProviders = listOf(CustomUserIdProvider()),
)
// Attach your own custom user_id field to each log
class CustomUserIdProvider implements FieldProvider {
@Override
public Map<String, ? extends String> invoke() {
return Collections.singletonMap("user_id", "<your_custom_user_id>");
}
}
Logger.start(
// ...
Collections.singletonList(new CustomUserIdProvider()) //fieldProviders
);
// Attach your own custom user_id field to each log
final class CustomUserIdProvider: FieldProvider {
func getFields() -> Fields {
["user_id": "<your_custom_user_id>"]
}
}
Logger.start(
// ...
fieldProviders: [CustomUserIdProvider()],
)
Tip
user_id is a one-of-a-kind special field. Providing it as shown above will cause it to appear in the Timeline header.