• Home
  • Integrations
  • SDKs
  • Guides
  • API docs
No results for ""
EXPAND ALL

GIVE DOCS FEEDBACK

Logging configuration

Read time: 19 minutes
Last edited: Feb 26, 2024

Overview

This topic explains how to configure the logging feature. Logging is available for client-side, server-side, and edge SDKs.

Configuring logging

LaunchDarkly SDKs rely on built-in logging packages and libraries to track events. Depending on which language you use, you can configure logging behavior to be highly or minimally verbose.

  • Client-side SDKs
  • Server-side SDKs
  • Edge SDKs

Client-side SDKs

This feature is available in the following client-side SDKs:

.NET (client-side)

Expand .NET (client-side) code sample

The client-side .NET SDK uses the Common.Logging framework. For an example configuration, read the Common.Logging README.

There are two important things to consider before you enable the DEBUG log level:

  1. Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.
  2. Debug-level logs include sensitive information, including LaunchDarkly contexts you create when you use this SDK.

Android

Expand Android code sample

The Android SDK makes heavy use of Timber logging. Include Timber in your application to enable debug output or production logging. An example is shown below to enable debug output when the application is built with a debug configuration.

Here's how:

if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}

C++ (client-side)

Expand C++ (client-side) code sample

By default, there is no log output, but we provide a default logger you can enable. The SDK does not lock on any logging. Ensure that your implementation is thread safe.

Whether you use a custom logger or the default one, you must use the LoggingBuilder to configure logging before the client is initialized. You cannot modify logging while the client is running.

If you use the default logger, you can configure how verbose it should be. The options are debug, info, warn, and error.

Here is an example:

auto config_builder = client_side::ConfigBuilder("mobile-key-123abc");
config_builder.Logging()
.Logging(LoggingBuilder::BasicLogging().Tag("ArbitraryLogTag").Level(LogLevel::kWarn));
auto config = config_builder.Build();

You can also use your own custom log function.

First, implement the log backend interface. For C++, this means implementing the ILogBackend interface. If you are working with the C binding, define the callback functions to implement the log backend interface.

Here's how:

#include <launchdarkly/logging/log_level.hpp>
#include <launchdarkly/logging/log_backend.hpp>
using namespace launchdarkly;
class CustomLogger : public ILogBackend {
public:
/* Should return true if the specified level is enabled; in this example, return true to log all messages. */
bool Enabled(LogLevel level) noexcept override { return true; }
/* Forwards to stdout as an example, printing the log tag along with the message. */
void Write(LogLevel level, std::string message) noexcept override {
std::cout << GetLogLevelName(level, "unknown") << ": " << message << std::endl;
}
};

Then, install the custom logger in the SDK's config:

// Make sure the <memory> header is included for std::make_shared
#include <memory>
auto config_builder = client_side::ConfigBuilder("mobile-key-123abc");
config_builder.Logging()
.Logging(LoggingBuilder::CustomLogging().Backend(std::make_shared<CustomLogger>()));
auto config = config_builder.Build();

Electron

Expand Electron code sample

By default, the SDK uses the winston package. There are four logging levels: debug, info, warn, and error. By default, debug messages are hidden.

To change the logging configuration, you can set LDOptions.logger to either another Winston instance or any object that implements the LDLogger interface. The createConsoleLogger function creates a minimal logger.

Flutter

Expand Flutter code sample

The Flutter SDK supports logging in version 4 and later.

There are four logging levels in the Flutter SDK: debug, info, warn, and error. You can also set the level to none to disable all logging.

By default, the SDK logs at the info level with a tag of "LaunchDarkly." To change the logging, construct an LDLogger and include it in your LDConfig. You can change the log level, tag, and output destinations when you construct the logger.

Here's how:

final logger = LDLogger(level: LDLogLevel.warn);
final config = LDConfig(
CredentialSource.fromEnvironment,
AutoEnvAttributes.enabled,
logger: logger,
);

Optionally, you can create a custom logging implementation. Your implementation should use the LDLogAdapter interface.

To learn more, read LDLogger.

JavaScript

Expand JavaScript code sample

In the default configuration, the SDK sends the output to the console and enables all log levels except debug.

To change the logging configuration, set LDOptions.logger to any object that implements the LDLogger interface and performs logging for the client. To learn more, read LDOptions and LDLogger in the SDK API docs.

Node.js (client-side)

Expand Node.js (client-side) code sample

The client-side Node.js SDK offers several choices for logging.

In the default configuration, the SDK sends output to the console and enables all log levels except debug.

Versions 1.x of the SDK used the winston logging package for the default configuration. Versions 2.0 and later do not have a dependency on winston. Instead, they write directly to the console by default.

For full control over logging behavior, you can set the logger option to an object that implements the LDLogger interface. To learn more about the logger's requirements and methods, read LDLogger. The winston package is compatible with this interface, so if you are already using a winston logger, you can pass it directly to the SDK.

You can use basicLogger for simpler control over logging behavior. Versions 2.x and earlier of the SDK do not support basicLogger.

This example shows how to use basicLogger to enable debug-level logging in your SDK configuration:

const LaunchDarkly = require('launchdarkly-node-client-sdk');
const options = {
logger: LaunchDarkly.basicLogger({
level: 'debug',
}),
};
const client = LaunchDarkly.initialize( 'client-side-id-123abc', user, options);

Be aware of two considerations when enabling debug-level logging:

  1. Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.
  2. Debug-level logs include sensitive information, including LaunchDarkly users you create when you use this SDK.

React Native

Expand React Native code sample

By default, the React Native SDK uses BasicLogger. This sends output to the console, with a default log level of info.

You can use BasicLogger to make some changes to logging behavior. For full control over logging behavior, you can set the LDOptions.logger option to an object that implements the LDLogger interface and performs logging for the client.

This example shows how to use BasicLogger to enable debug-level logging in your SDK configuration:

import {
AutoEnvAttributes,
BasicLogger,
type LDOptions,
ReactNativeLDClient,
} from '@launchdarkly/react-native-client-sdk';
const options: LDOptions = {
logger: new BasicLogger({
level: 'debug',
destination: console.log,
}),
};
const featureClient = new ReactNativeLDClient('mobile-key-123abc', AutoEnvAttributes.Enabled, options);

To learn more, read LDOptions and LDLogger.

React Web

Expand React Web code sample

The React Web SDK relies on the JavaScript SDK for logging-related functionality. In the default configuration, the SDK sends the output to the console and enables all log levels except debug.

To change the logging configuration, set LDOptions.logger to any object that implements the LDLogger interface and performs logging for the client. The basicLogger, available in the JavaScript SDK, produces such an object.

Here's how:

import { basicLogger } from 'launchdarkly-js-client-sdk';
export default withLDProvider({
clientSideID: 'client-side-id-123abc',
options: {
logger: basicLogger({level: 'debug'})
}
})(App);

To learn more, read LDOptions and LDLogger in the JavaScript SDK API docs.

Roku

Expand Roku code sample

The Roku SDK's logging feature is configurable. You can set different log levels, or use a custom logging backend with one of the two supported custom loggers.

Those loggers are:

Log levels in the Roku SDK


You can configure the SDK log level. For example, to set the level to info:

config.setLogLevel(LaunchDarklyLogLevels().info)

The SDK supports the following Levels:

LaunchDarklyLogLevels().error
LaunchDarklyLogLevels().warn
LaunchDarklyLogLevels().info
LaunchDarklyLogLevels().debug
LaunchDarklyLogLevels().none

Legacy API custom logger for the Roku SDK


Here is an example of the legacy API custom logger:

function CustomLogger() as Object
return {
log: function(level as Integer, message as String)
print level message
end function
}
end function
config.setLogger(CustomLogger())

SceneGraph API custom logger for the Roku SDK


Here is an example of the SceneGraph API custom logger:

<!-- /components/CustomLogger.xml -->
<component name="CustomLogger" extends="Task">
<interface>
<field id="log" type="assocarray" alwaysNotify="true"/>
</interface>
<script type="text/brightscript" uri="pkg:/components/CustomLogger.brs"/>
</component>

To use the logger, create the SceneGraph logger node, and then:

config.setLoggerNode(myLoggerNode)

Server-side SDKs

This feature is available in the following server-side SDKs:

.NET (server-side)

Expand .NET (server-side) code sample

The .NET SDK has four logging levels: Debug, Info, Warn, and Error. By default, the lowest enabled level is Info, so Debug messages are hidden. There are two important things to consider if you enable the Debug level:

  1. Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.
  2. Debug-level logs include sensitive information, including LaunchDarkly contexts you create when you use this SDK.

The .NET SDK sends log output to Console.Error by default. The ConfigurationBuilder.Logging method and the LaunchDarkly.Logging API allow you to change the output destination and log level.

Here is an example:

using LaunchDarkly.Logging;
using LaunchDarkly.Sdk.Server;
var config = Configuration.Builder("sdk-key-123abc")
.Logging(
Components.Logging(Logs.ToWriter(Console.Out)).Level(LogLevel.Debug)
)
.Build();

The destination could be another logging framework, such as the .NET Core Microsoft.Extensions.Logging API in this example:

using LaunchDarkly.Logging;
using LaunchDarkly.Sdk.Server;
var config = Configuration.Builder("sdk-key-123abc")
.Logging(Logs.CoreLogging)
.Build();

To learn more about logging configuration and adapters for other logging frameworks, read the documentation for LaunchDarkly.Logging.

All log messages from the SDK are tagged with a logger name, indicating the category of messages. If you use a logging framework like Microsoft.Extensions.Logging or NLog, you can use these names to filter the output:

  • LaunchDarkly.Sdk: general messages about the operation of the SDK client.
  • LaunchDarkly.Sdk.DataSource: messages about how the SDK client receives feature flag data, such as if the connection to LaunchDarkly has been interrupted.
  • LaunchDarkly.Sdk.DataStore (or more specific names like LaunchDarkly.Sdk.DataStore.Redis): messages about how the SDK client stores feature flag data, such as if you are using a database integration.
  • LaunchDarkly.Sdk.Evaluation: messages about unusual conditions during feature flag evaluation, such as if a feature flag could not be evaluated because its configuration is invalid.
  • LaunchDarkly.Sdk.Events: messages about analytics events, such as if event data could not be sent to LaunchDarkly due to a network problem.

Before version 6.0, the .NET SDK had different logging behavior:

  • The mechanism for specifying a log destination was the Common.Logging framework.
  • If you did not specifically configure a log destination using Common.Logging, logging was disabled by default.
  • The main logger name was LaunchDarkly.Client.LdClient.

C++ (server-side)

Expand C++ (server-side) code sample

By default, there is no log output, but we provide a default logger you can enable. The SDK does not lock on any logging. Ensure that your implementation is thread safe.

Whether you use a custom logger or the default one, you must use the LoggingBuilder to configure logging before the client is initialized. You cannot modify logging while the client is running.

If you use the default logger, you can configure how verbose it should be. The options are debug, info, warn, and error.

Here is an example:

auto config_builder = server_side::ConfigBuilder("sdk-key-123abc");
using LoggingBuilder = server_side::config::builders::LoggingBuilder;
config_builder.Logging().Logging(
LoggingBuilder::BasicLogging().Tag("ArbitraryLogTag").Level(LogLevel::kWarn)
);

You can also use your own custom log function.

First, implement the log backend interface. For C++, this means implementing the ILogBackend interface. If you are working with the C binding, define the callback functions to implement the log backend interface.

Here's how:

#include <launchdarkly/logging/log_level.hpp>
#include <launchdarkly/logging/log_backend.hpp>
using namespace launchdarkly;
class CustomLogger : public ILogBackend {
public:
/* Should return true if the specified level is enabled; in this example, return true to log all messages. */
bool Enabled(LogLevel level) noexcept override { return true; }
/* Forwards to stdout as an example, printing the log tag along with the message. */
void Write(LogLevel level, std::string message) noexcept override {
std::cout << GetLogLevelName(level, "unknown") << ": " << message << std::endl;
}
};

Then, install the custom logger in the SDK's config:

// Make sure the <memory> header is included for std::make_shared
#include <memory>
config_builder.Logging().Logging(LoggingBuilder::CustomLogging().Backend(
std::make_shared<CustomLogger>()));
auto config = config_builder.Build();

Go

Expand Go code sample

The Go SDK uses a logging abstraction that can write to a log.Logger or anything with a compatible interface. This adds a system of log levels similar to logging frameworks on other platforms. There are four logging levels: Debug, Info, Warn, and Error.

By default, all levels of messages are enabled except Debug. You can tell the SDK to enable more or fewer levels, to send the output to a different destination, or to disable logging.

Here's how:

import (
"log"
"os"
ldlog "github.com/launchdarkly/go-sdk-common/v3"
ld "github.com/launchdarkly/go-server-sdk/v6"
"github.com/launchdarkly/go-server-sdk/v6/ldcomponents"
)
var config ld.Config
loggers := ldlog.NewDefaultLoggers()
// Send output to a file
file, _ := os.Create("app.log")
loggers.SetBaseLogger(log.New(file, "", log.LstdFlags))
config.Logging = ldcomponents.Logging().
Loggers(loggers).
MinLevel(ldlog.Warn) // Change minimum level to Warn (Debug and Info are disabled)
// Or, disable logging
config.Logging = ldcomponents.NoLogging()

There are two things to consider if you enable the Debug log level:

  1. Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.
  2. Debug-level logs include sensitive information, including LaunchDarkly contexts you create when you use this SDK.

Java

Expand Java code sample

In version 5.10.0 and higher, the Java SDK allows you to specify a destination for logging using the LDConfig.Builder.logging method and the com.launchdarkly.logging API.

If you do not specify a destination, the default behavior depends on the version of the SDK:

  • In versions 5.10.0 and earlier, the default destination is SLF4J. SLF4J has its own configuration mechanisms for determining where output will go, and for filtering by level and/or logger name. It will not generate any output unless you have provided a configuration. For an example of using SLF4J with a simple console logging configuration, visit an SLF4J-specific version of hello-java.
  • Starting with version 6.0.0, the SDK does not require SLF4J. Instead, it detects whether the application is already using SLF4J. If the SLF4J classes are present in the classpath, then it sends log output to SLF4J by default. If the SLF4J classes are not present in the classpath, then it sends log output to System.err by default.

Here is an example of configuring log output to go to the standard output stream (System.out), and enabling DEBUG level:

import com.launchdarkly.logging.*;
import com.launchdarkly.sdk.server.*;
LDConfig config = new LDConfig.Builder()
.logging(
Components.logging(Logs.toStream(System.out)).level(LDLogLevel.DEBUG)
)
.build();

To learn more about logging configuration and adapters for other logging frameworks, read the documentation for com.launchdarkly.logging.

All log messages from the SDK are tagged with a logger name, indicating the category of messages. If you use a logging framework like SLF4J, you can use these names to filter the output:

  • com.launchdarkly.sdk.server.LDClient: This is for general messages that do not fall into any other categories.
  • com.launchdarkly.sdk.server.LDClient.DataSource: This is for messages related to how the SDK obtains feature flag data. Usually, this means messages about the streaming connection to LaunchDarkly, but if you use polling mode or file data instead, the SDK logs those messages under this name.
  • com.launchdarkly.sdk.server.LDClient.DataStore: This is for messages related to how feature flag data is stored. For example, database errors appear here if you are using a database integration.
  • com.launchdarkly.sdk.server.LDClient.Evaluation: This is for messages related to feature flag evaluation.
  • com.launchdarkly.sdk.server.LDClient.Events: This is for messages related to analytics event processing.

In versions of the SDK before 5.0, logger names were not standardized and were sometimes the names of Java classes that are not part of the public API, but they consistently had a package prefix of either com.launchdarkly.client. or com.launchdarkly.eventsource.

There are two important things to consider before you enable the DEBUG log level:

  1. Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.
  2. Debug-level logs include sensitive information, including LaunchDarkly contexts you create when you use this SDK.

Lua

Expand Lua code sample

The SDK configures a default logger if not otherwise specified. You may modify the behavior of the default logger by specifying a custom log tag and minimum log level, or you may completely replace it with a custom logging implementation.

The SDK does not lock on any logging, so ensure that your custom implementation is thread safe.

You cannot modify logging while the client is running.

If you use the default logger, you can configure how verbose it should be. The options are 'debug', 'info', 'warn', and 'error'.

Here is an example:

local config = {
logging = {
basic = {
tag = "launchdarkly",
level = "warn"
}
}
}

You can also use a custom logger. Here's how:

local logger = ld.makeLogBackend(
function(level)
-- Log everything.
return true
end,
function(level, message)
-- Prints in the format: '[level] hello world'
print(string.format("[%s] %s", level, message))
end
)
local config = {
logging = {
custom = logger
}
}

Node.js (server-side)

Expand Node.js (server-side) code sample

The Node.js SDK offers several choices for logging.

In the default configuration, the SDK sends output to the console and enables all log levels except debug.

Pre-6.0 versions of the SDK used the winston logging package for the default configuration. Versions 6.0 and later write directly to the console by default.

For full control over logging behavior, you can set the logger option to an object that implements the LDLogger interface. To learn more about the logger's requirements and methods, read LDLogger.

You can use basicLogger for simpler control over logging behavior. Versions 5.x and earlier of the SDK do not support basicLogger.

This example shows how to use basicLogger to enable debug-level logging in your SDK configuration:

import * as ld from '@launchdarkly/node-server-sdk';
const logger: ld.LDLogger = ld.basicLogger({
level: 'debug',
destination: console.log,
});
const options: ld.LDOptions = { logger: logger };

There are two important things to consider before you enable debug-level logging:

  1. Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.
  2. Debug-level logs include sensitive information, including LaunchDarkly users you create when you use this SDK.

PHP

Expand PHP code sample

The PHP SDK uses Monolog. All loggers are namespaced under LaunchDarkly.

There are two important things to consider before you enable the DEBUG log level:

  1. Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.
  2. Debug-level logs include sensitive information, including LaunchDarkly contexts you create when you use this SDK.

You can pass a custom logger to the SDK by using the configurable logger property:

$client = new LaunchDarkly\LDClient("sdk-key-123abc", ["logger" => new Logger("LaunchDarkly", [new ErrorLogHandler(0, Level::Debug)])]);

Python

Expand Python code sample

The Python SDK uses Python's built-in logging library.

Here's how to enable the debug log level:

ld_logger = logging.getLogger("ldclient")
ld_logger.setLevel(logging.DEBUG)

There are two important things to consider before you enable the debug log level:

  • Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.
  • Debug-level logs include sensitive information, including LaunchDarkly users you create when you use this SDK.

Ruby

Expand Ruby code sample

The Ruby SDK uses Ruby's built-in Logger class. All loggers are namespaced under [LDClient].

There are two important things to consider before you enable the DEBUG log level:

  1. Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.

  2. Debug-level logs include sensitive information, including LaunchDarkly contexts you create when you use this SDK.

    You can pass a custom logger to the SDK by using the configurable logger property:

    log = ::Logger.new($stdout)
    log.level = ::Logger::DEBUG
    config = LaunchDarkly::Config.new({logger: log})
    client = LaunchDarkly::LDClient.new("sdk-key-123abc", config)

Rust

Expand Rust code sample

The Rust SDK uses the log crate.

There are two important things to consider before you enable the DEBUG log level:

  1. Debug-level logs can be very verbose. We do not recommend using debug logging in high-volume environments.
  2. Debug-level logs include sensitive information, including LaunchDarkly contexts you create when you use this SDK.

Edge SDKs

This feature is available in the following edge SDKs:

Cloudflare

Expand Cloudflare code sample

In the default configuration, the SDK sends output to the console and enables all log levels except debug.

For full control over logging behavior, you can set the logger option to an object that implements the LDLogger interface. To learn more about the logger's requirements and methods, read LDLogger.

This example shows how to use BasicLogger to enable debug-level logging in your SDK configuration:

import { BasicLogger, LDOptions } from '@launchdarkly/cloudflare-server-sdk';
const options: LDOptions = {
logger: new BasicLogger({ level: 'debug', }),
};

Vercel

Expand Vercel code sample

In the default configuration, the SDK sends output to the console and enables all log levels except debug.

This example shows how to use BasicLogger to enable debug-level logging in your SDK configuration:

import { BasicLogger, LDOptions } from '@launchdarkly/vercel-server-sdk';
const options: LDOptions = {
logger: new BasicLogger({ level: 'debug', }),
};

For full control over logging behavior, you can set the logger option to an object that implements the LDLogger interface. To learn more about the logger's requirements and methods, read LDLogger.