Skip to content

    Minimalistic Logging Facade

    cds.log (module name) Logger

    Returns a trace logger for the given module if trace is switched on for it, otherwise returns null. All cds runtime packages use this method for their trace and debug output.

    It can also be used in applications as follows.

    const LOG = cds.log('sql')
    LOG._info && ('whatever', you, 'like...')

    You can also specify alternate module names: const LOG = cds.log('db|sql')

    You can set log levels per module via cds.env.log.levels = { <module>: <level> }:

    cds.env.log.levels = { app: 'warn', db: 'debug' }

    Learn more about cds.env.

    Further, tracing can be switched on/off through env variable DEBUG. Set it to a comma-separated list of modules to switch on tracing. Set it to ‘all’ or ‘y’ to switch on tracing for all modules.


    • module: the module for which a logger is requested
    • level?: the log level to enable -> 0=off, 1=error, 2=warn, 3=info, 4=debug, 5=trace, default: 3
    • prefix?: a prefix to prepend to each log output, default: [cds.<module>] -

    Capture Stack Trace with SQLite

    With env variable DEBUG set to ‘sqlite’, you can activate capturing the stack trace on the way to executing a query.

    Logger factory cds.log.Logger

    Constructs a new logger with the method signature of { trace, debug, log, info, warn, error } (cf. console). Additionally, the returned logger indicates which levels are active through a corresponding underscored property, for example, cds.log('sqlite')._debug is truth if the logger for module “sqlite” is set to at least debug level.

    The default implementation maps to console.error(), which prints to stderr. You can assign different implementations by exchanging the factory with your own, for example, in order to integrate advanced logging frameworks such as winston.


    • module: the module for which a logger is requested
    • level: the log level to enable -> 0=off, 1=error, 2=warn, 3=info, 4=debug, 5=trace
    • prefix?: a prefix to prepend to each log output, default: [cds] -


    cds.log.Logger = (module, level, prefix) => {
      const logger = winston.createLogger(...)
      Object.assign(logger, {
        _trace: false,
        _debug: false,
        _info: false,
        _warn: true,
        _error: true
      return logger

    Log Formatter cds.log.format

    You can provide a custom log formatter function by setting cds.log.format programmatically as shown, for example in your custom server.js.

    The formatter shall return an array of arguments, which are passed to the logger (for example, console.log()):

    cds.log.format = (module, level, ...args) => {
      return [`${module} //>`, util.format(...args)]

    Out-of-the-box Log Formatting

    Log formatting can best be illustrated by examples. Hence, we look at the following example dummy logs from the CAP SFLIGHT app context, in which a warning with multiple arguments is issued and the request subsequently rejected with an error:

    const cds = require('@sap/cds')
    const LOG = cds.log('travel-service')
    class TravelService extends cds.ApplicationService {
    init() {
      this.before('READ', 'Travel', req => {
        LOG.warn('I will throw a test error.', { Do: 'not' }, 'panic.')
        req.reject('I will provoke a test error to be thrown.')

    Default Formatter

    During development, we want short messages in the console with clickable stack traces in case of errors. You should not be overloaded with information that is additionally obfuscated by a bad rendering. Hence, console.log(), that makes use of util.format() out of the box, with raw arguments is a good choice.

    The default log formatter does exactly that, prepending the list of arguments with [<module> -]. The following screenshot shows the log output for the previous warning and rejection with the default log formatter.

    Default Formatter Output

    Kibana-Friendly Formatter

    In production, DevOps typically consume application logs via dashboards such as Kibana or Grafana. Hence, the log output needs to be formatted in a way that enables the respective dashboard technology to optimally support the user, for example, filtering for logs of specific levels, modules, status, etc.

    The Kibana-friendly log formatter constructs a loggable object from the passed arguments as well as cds.context and the headers of the incoming request (if available).

    Kibana-friendly log formatting can be added using cds add kibana-logging. Alternatively, it can be activated via cds.env.features.kibana_formatter = true. In the future, the Kibana-friendly formatter will become the default when running in SAP BTP and bound to an instance of the SAP Application Logging Service for the Cloud Foundry Environment.

    The following screenshot shows the log output for the rejection in the previous example with the Kibana-friendly log formatter.

    Kibana-friendly Formatter Output


    The following configuration options can be applied:

    • cds.env.log.user = true: Log the user’s ID ( as remote_user (Kibana formatter only). Consider the data privacy implications!
    • cds.env.log.sanitize_values = false: By default, payload data is sanitized in debug logs while running in production. Sanitization can be deactivated by setting to false.

    Request and Log Correlation

    Unfortunately, there is no standard correlation ID header. x-correlation-id and x-request-id are the most commonly used, but SAP products often use x-correlationid (that is, without the second hyphen) and SAP BTP uses x-vcap-request-id when logging incoming requests.

    As CAP aims to be platform independent, we check an array of headers (or generate a new ID if none hits) and ensure the value available at as well as req.headers['x-correlation-id']:

    const { headers: h } = req = h['x-correlation-id'] || h['x-correlationid']
      || h['x-request-id'] || h['x-vcap-request-id']
      || uuid()
    req.headers['x-correlation-id'] =

    The following screenshot shows an example for log correlation in Kibana .

    Default Formatter Output

    Module Names Used by the Runtime

    The runtime uses the same logger facade, that is cds.log(). For each component, it requires a separate logger. So projects can set different log levels for different components/layers. The following table lists the module names used to set the log levels:

    Component Module Name(s)
    Application Service app
    SQLite Database db|sql|sqlite
    SAP HANA Database db|sql|hana
    Messaging Service messaging
    Remote Service remote
    OData protocol adapter odata
    REST protocol adapter rest
    GraphQL protocol adapter graphql
    Request logging on CLI cds (for example: GET /foo)

    Fallback is always cds.


    I am interested in the requests sent to remote services (logged with debug level), but don’t care about executed SQL statements. If I set the global level to debug, I’d get both. This is what I need to do:

    1. Set cds.env.log.levels.remote = debug
    2. Keep cds.env.log.levels.db at the default info