Skip to main content

Elastic Stack (ELK)

The Elastic Stack (Elasticsearch, Logstash, Kibana) provides powerful log aggregation, search, and visualization for your Ballerina integrations. Use it to centralize logs, analyze request patterns, and create operational dashboards.

Prerequisites

RequirementDetails
ElasticsearchVersion 8.x or later
LogstashVersion 8.x (optional, Filebeat can replace it)
KibanaVersion 8.x
FilebeatVersion 8.x (recommended for log shipping)

Architecture

Ballerina Integration ──▶ Log Files ──▶ Filebeat ──▶ Elasticsearch ──▶ Kibana

(optional) ──▶ Logstash ─┘

Step 1 -- configure Ballerina logging

Enable structured JSON logging in Config.toml:

[ballerina.log]
level = "INFO"

Emit structured log entries in your code:

import ballerina/log;

service /api on new http:Listener(9090) {
resource function post orders(http:Request req) returns json|error {
json payload = check req.getJsonPayload();
string orderId = check payload.orderId;

log:printInfo("Order received",
orderId = orderId,
source = "api",
action = "create"
);

// Process order...
json result = check processOrder(payload);

log:printInfo("Order processed",
orderId = orderId,
status = "success"
);

return result;
}
}

Step 2 -- install and configure filebeat

Install Filebeat to ship logs to Elasticsearch:

# Install Filebeat
curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.11.0-linux-x86_64.tar.gz
tar xzvf filebeat-8.11.0-linux-x86_64.tar.gz

Configure filebeat.yml:

filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/integrations/*.log
json.keys_under_root: true
json.add_error_key: true
fields:
service: order-service
environment: production

output.elasticsearch:
hosts: ["http://elasticsearch:9200"]
index: "ballerina-integrations-%{+yyyy.MM.dd}"

setup.kibana:
host: "http://kibana:5601"

Start Filebeat:

./filebeat -e

Step 3 -- configure Logstash (Optional)

For advanced log processing, use Logstash between Filebeat and Elasticsearch:

input {
beats {
port => 5044
}
}

filter {
json {
source => "message"
}
date {
match => ["timestamp", "ISO8601"]
target => "@timestamp"
}
mutate {
add_field => { "pipeline" => "ballerina-integration" }
}
}

output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "ballerina-integrations-%{+yyyy.MM.dd}"
}
}

Step 4 -- create Kibana dashboards

Index pattern

  1. Open Kibana and navigate to Stack Management > Index Patterns.
  2. Create a pattern: ballerina-integrations-*.
  3. Select @timestamp as the time field.

Useful visualizations

VisualizationTypeDescription
Log VolumeArea chartLog entries over time by level
Error LogsData tableRecent ERROR-level log entries
Service MapPie chartLog distribution by service
Response TimesLine chartAverage response duration over time

Sample KQL queries

QueryPurpose
level: "ERROR"Find all error logs
service: "order-service" AND orderId: "ORD-123"Trace a specific order
level: "ERROR" AND NOT message: "timeout"Errors excluding timeouts

Docker compose setup

version: "3.8"
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- "9200:9200"
volumes:
- es-data:/usr/share/elasticsearch/data

kibana:
image: docker.elastic.co/kibana/kibana:8.11.0
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
depends_on:
- elasticsearch

filebeat:
image: docker.elastic.co/beats/filebeat:8.11.0
volumes:
- ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
- /var/log/integrations:/var/log/integrations:ro
depends_on:
- elasticsearch

volumes:
es-data:

What's next