Centralized Logging Solution using FireLens and Fluent Bit for ECS
David Chou @ Golang Taipei


@ Umbo Computer Vision
@ Golang Taipei

david74.chou @ facebook
david74.chou @ medium
david7482 @ github

Golang Taipei Telegram

Golang Taipei Facebook
Why do we need centralized logging?
Why do we need centralized logging?
-
Usability
-
Availability
-
Analyzability

Centralized logging architecture







-
Implemented in Ruby/C @ 2011
-
Ecosystem of Plugins (900+)
-
Extend with Ruby
-
Memory Usage (40MB)
-
Higher CPU Usage
-
Better for Aggregation
-
Support Forward Protocol
-
Implemented in C @ 2015
-
Plugins are Included (56)
-
Extend with C/Go/Lua
-
Reduced Memory Usage (500KB)
-
Lower CPU Usage
-
Better as a Sidecar
-
Support Forward Protocol






Input
Parser
Filter
Buffer
Output 1
Output 2
Output N
Routing

Input
Parser
Filter
Output 1
Output 2
Output N
Information gathering,
e.g. forward, tail, syslog, memory
Buffer
Routing

Input
Parser
Filter
Output 1
Output 2
Output N
Unstructured logs => Structured binary format,
e.g. json, regx (nginx, syslog, etc)
Buffer
Routing

Input
Parser
Filter
Output 1
Output 2
Output N
Input data manipulation,
e.g. grep, record_modifier
Buffer
Routing

Input
Parser
Filter
Output 1
Output 2
Output N
Message buffering & retry
Buffer
Routing

Input
Parser
Filter
Output 1
Output 2
Output N
Tag routing
Buffer
Routing

Input
Parser
Filter
Output 1
Output 2
Output N
Send data to different destinations,
e.g. forward, es, Go plugins
Buffer
Routing
How to write a Fluent Bit Go plugin?
Fluent Bit Go Plugin


fluent-bit
plugin.so
dynamic loading
//export FLBPluginRegister
func FLBPluginRegister(def unsafe.Pointer) int {
// Gets called only once when the .so is loaded.
return output.FLBPluginRegister(def, "gstdout", "Stdout GO!")
}
//export FLBPluginInit
func FLBPluginInit(plugin unsafe.Pointer) int {
// Gets called once for each instance you have configured.
param := output.FLBPluginConfigKey(plugin, "param")
return output.FLB_OK
}
//export FLBPluginFlushCtx
func FLBPluginFlushCtx(ctx, data unsafe.Pointer, length C.int, tag *C.char) int {
// Gets called once for each message to be written to an instance.
}
//export FLBPluginExit
func FLBPluginExit() int {
// Gets called on teardown.
return output.FLB_OK
}
func main() {
}# Build fluent bit go plugin
$ go build -o plugin.so -buildmode c-shared plugin.go
# Run Fluent Bit with the new plugin
$ fluent-bit -e plugin.so -i cpu -o gstdout# Build fluent bit go plugin
$ go build -o plugin.so -buildmode c-shared plugin.go
# Run Fluent Bit with the new plugin
$ fluent-bit -e plugin.so -i cpu -o gstdoutGo build modes
-
default
-
archive
-
exe
-
pie
-
shared
-
plugin
-
c-archive
-
c-shared
AWS FireLens
AWS FireLens
-
Support a wide-array of AWS Services as log destinations
-
Require no additional configuration beyond ECS Task Definition
-
Use Open Source for extensibility: Fluent Bit, Fluentd
-
Facilitate partner integration
AWS for Fluent Bit
-
A Fluent Bit image with AWS Go plugins
-
amazon/aws-for-fluent-bit on Docker Hub
-
Regional public images hosted on ECR
AWS for Fluent Bit - Log destination
- Kinesis Data Firehose
- S3
- Amazon ElasticSearch Service
- Kinesis Data Streams
- CloudWatch Logs
- Kafka
- Self-hosted ElasticSearch (#698)
- DataDog
- Forward to a Fluentd aggregator
AWS for Fluent Bit - Log destination
$ cat entrypoint.sh
exec /fluent-bit/bin/fluent-bit \
-e /fluent-bit/firehose.so \
-e /fluent-bit/cloudwatch.so \
-e /fluent-bit/kinesis.so \
-c /fluent-bit/etc/fluent-bit.confUse AWS FireLens in ECS

{
"essential": true,
"image": "amazon/aws-for-fluent-bit:latest",
"name": "log_router",
"firelensConfiguration": {
"type": "fluentbit",
"options": {
"enable-ecs-log-metadata": "true",
"config-file-type": "file",
"config-file-value": "/json.conf"
}
}
},
{
"essential": true,
"image": "<your-app-image>",
"name": "app",
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"Name": "cloudwatch",
"region": "us-west-2",
"log_group_name": "firelens-fluent-bit",
"log_stream_prefix": "from-fluent-bit",
"include-pattern": "[Ee]rror"
}
}
}[INPUT]
Name forward
unix_path /var/run/fluent.sock
[INPUT]
Name forward
Listen 0.0.0.0
Port 24224
[FILTER]
Name grep
Match app-firelens*
Regex log [Ee]rror
[FILTER]
Name record_modifier
Match *
Record ecs_cluster firelens-example
Record ecs_task_arn arn:aws:ecs:us-west-2:0123456789:task/1111
Record ecs_task_definition firelens-example-session:5
@INCLUDE /json.conf
[OUTPUT]
Name cloudwatch
Match app-firelens*
region us-west-2
log_group_name firelens-fluent-bit
log_stream_prefix from-fluent-bit
ECS task defition
fluent-bit.conf
FireLens internal


FireLens internal
- ECS generates the Fluent Bit config file in Firelens container
- /fluent-bit/etc/fluent-bit.conf
-
Fluent TCP interface
- FLUENT_HOST (127.0.0.1), FLUENT_PORT (24224)
- Use SDK to send logs into Fluent Bit instead of stdout
FireLens internal
-
FireLens tag
- <container name>-firelens-<task ID>
- app-firelens-dcef9dee-d960-4af8-a206-46c31a7f1e67
- Currently, cannot customized this tag
- Workaround
- Fluent Bit stream processor
- CREATE STREAM myTag WITH (tag='myTag') AS SELECT * from TAG:'app-firelens-*'
- <container name>-firelens-<task ID>
FireLens log loss test

FireLens resource usage

Future improvement
Future improvement
-
Enhance the reliability of FireLens on Fargate (#700)
- Logs could be lost if Fluent Bit container goes down unexpectedly
- Firelens container needs to be essential
- Fargate containers are ephemeral
- Better Support for Multiple Go Plugins
$ ls -lh bin/fluent-bit *.so
root root 18M Dec 12 23:14 bin/fluent-bit
root root 24M Jan 08 20:50 cloudwatch.so
root root 26M Dec 12 23:04 firehose.so
root root 26M Dec 12 23:03 kinesis.soFuture improvement
- Better Support for Multiple Go Plugins

Future improvement
- Better Support for Multiple Go Plugins

Future improvement
Any Question?


Golang Taipei Telegram

Golang Taipei Facebook
問卷往這邊!!
Centralized Logging Solution using FireLens and Fluent Bit for ECS
By Ting-Li Chou
Centralized Logging Solution using FireLens and Fluent Bit for ECS
- 571