Bind Application Logging, configure @sap/logging middleware, emit structured JSON with correlation IDs, and query Kibana.
console.log@sap/logging to emit structured log entries with correlation IDsconsole.log writes to stdout. On Cloud Foundry you can read stdout with cf logs, but logs disappear when the app restarts and you cannot search across instances. SAP Application Logging Service ships every log line to an Elasticsearch cluster with a Kibana UI. Structured JSON logs let you filter by tenant, user, request ID, or error level — turning a flood of text into queryable operational intelligence.
cf create-service application-logs standard my-app-logs
cf bind-service my-cap-app my-app-logs
MTA:
resources:
- name: my-app-logs
type: org.cloudfoundry.managed-service
parameters:
service: application-logs
service-plan: standard
Once bound, the @sap/logging library auto-detects the binding and configures the transport — you do not need to supply credentials in code.
@sap/loggingnpm install @sap/logging
// srv/server.js
const logging = require('@sap/logging');
const cds = require('@sap/cds');
cds.on('bootstrap', app => {
// Attach the logging middleware — adds correlation ID to every request
app.use(logging.middleware({ app }));
});
// srv/purchase-order-service.js
const cds = require('@sap/cds');
const logging = require('@sap/logging');
module.exports = class PurchaseOrderService extends cds.ApplicationService {
async init() {
const { PurchaseOrders } = this.entities;
this.before('CREATE', PurchaseOrders, async req => {
// Get a logger scoped to this request (carries correlation ID automatically)
const logger = logging.createLogger({ layer: 'purchase-order-service' });
logger.info('Creating purchase order', {
user: req.user.id,
supplier: req.data.supplierId,
totalAmount: req.data.totalAmount
});
if (req.data.totalAmount > 1_000_000) {
logger.warn('Very large purchase order', {
amount: req.data.totalAmount,
currency: req.data.currency
});
}
});
this.on('error', (err, req) => {
const logger = logging.createLogger({ layer: 'purchase-order-service' });
logger.error('Unhandled error in PurchaseOrderService', {
error: err.message,
stack: err.stack,
user: req.user?.id,
path: req.path
});
});
await super.init();
}
};
| Level | Method | When to use |
|---|---|---|
| DEBUG | logger.debug() |
Verbose diagnostic — disabled in production |
| INFO | logger.info() |
Normal operations — request received, entity created |
| WARNING | logger.warn() |
Unexpected but recoverable — large transaction, slow query |
| ERROR | logger.error() |
Caught errors that were handled — validation failure |
| FATAL | logger.fatal() |
Unrecoverable errors — service cannot start |
Set the minimum level via env var:
# In manifest.yml
env:
SAP_LOG_LEVEL: warn # only warn, error, fatal in production
Every HTTP request that goes through the logging.middleware() gets a correlation ID — either from the X-CorrelationID header (if the caller is another BTP service) or auto-generated. The ID is injected into every log line from that request, so you can trace a single user action across multiple log entries:
{
"level": "INFO",
"msg": "Creating purchase order",
"correlationId": "abc-123-def",
"layer": "purchase-order-service",
"user": "P0012345",
"totalAmount": 45000
}
In Kibana, filter correlationId: "abc-123-def" to see every log from that one request.
Navigate to: BTP Cockpit → Services → Application Logging → Open Dashboard (Kibana)
Useful Kibana queries:
# All errors in the last hour
level: ERROR AND @timestamp:[now-1h TO now]
# Specific user's actions
user: "P0012345"
# Slow requests (custom field you logged)
durationMs: [500 TO *]
# By correlation ID
correlationId: "abc-123-def"
In Kibana create a Watcher (Elasticsearch alerting):
1. Go to Stack Management → Watcher → Create Threshold Alert
2. Index: cap-app-logs-*
3. Condition: COUNT(level:ERROR) > 10 within 5 minutes
4. Action: send email / call webhook
Or use SAP Alert Notification Service (Episode 60) to route alerts raised from your CAP error handlers.
| Mistake | Fix |
|---|---|
console.log in production |
Use @sap/logging — console.log is not structured |
Not attaching logging.middleware() |
Correlation IDs will not be populated |
| Logging sensitive data (passwords, tokens) | Scrub PII before logging — GDPR applies |
| DEBUG level in production | Set SAP_LOG_LEVEL=warn in production manifest |
| Logging inside a tight loop | Log at entry/exit points, not per-iteration |
You can bind SAP Application Logging Service, configure @sap/logging middleware, emit structured log entries with correlation IDs from CAP handlers, and query logs in Kibana by level, user, or correlation ID. You know how to set an appropriate log level for production.