Giter Club home page Giter Club logo

shim-loggers-for-containerd's Introduction

Shim loggers for containerd

PkgGoDev Go Report Card Build Static Badge

Shim loggers for containerd is a collection of containerd compatible logger implementations that send container logs to various destinations. The following destinations are currently supported:

Build

Make sure you have golang installed. Then simply run make build to build the respective binaries. You might need to execute make get-deps to install some of the dependencies.

Usage

Containerd supports shim plugins that redirect container output to a custom binary on Linux using STDIO URIs with runc v2 runtime. These loggers can be used either programmatically or with the ctr tool.

When using the NewTask API

When using the NewTask API to start a container, simply provide the path to the built binary file shim-loggers-for-containerd and required arguments. Note it's a good practice to clean up container resources with Delete API call after container exited as the container IO pipes are not closed if the shim process is still running.

Example:

NewTask(context, cio.BinaryIO("/usr/bin/shim-loggers-for-containerd", args))

When using the ctr tool

When using ctr tool to run a container, provide the URI path to the binary file shim-loggers-for-containerd and required arguments as part of the path.

Example:

ctr run \
    --runtime io.containerd.runc.v2 \
    --log-uri "binary:///usr/bin/shim-loggers-for-containerd?--log-driver=awslogs&--arg1=value1&-args2=value2" \
    docker.io/library/redis:alpine \
    redis

Arguments

Common arguments

The following list of arguments apply to all of the shim logger binaries in this repo:

Name Required Description
log-driver Yes The name of the shim logger. Can be any of awslogs, splunk or fluentd.
container-id Yes The container id
container-name Yes The name of the container
mode No Either blocking or non-blocking. In the non-blocking mode, log events are buffered and the application continues to execute even if these logs can't be drained or sent to the destination. Logs could also be lost when the buffer is full.
max-buffer-size No Only supported in non-blocking mode. Set to 1m (1MiB) by default. Example values: 200, 4k, 1m etc.
uid No Set a custom uid for the shim logger process. 0 is not supported.
gid No Set a custom gid for the shim logger process. 0 is not supported.
cleanup-time No Set a custom time for the shim logger process clean up itself. Set to 5s (5 seconds) by default. Note the maximum supported value is 12 seconds, since containerd shim sets shim logger cleanup timeout value as 12 seconds. See reference.
container-image-id No The container image id. This is part of the docker config variables that can be logged by splunk log driver.
container-image-name No The container image name. This is part of the docker config variables that can be logged by splunk log driver.
container-env No The container environment variables map in json format. This is part of the docker config variables that can be logged by splunk log driver.
container-labels No The container labels map in json format. This is part of the docker config variables that can be logged by splunk log driver.

Windows specific arguments

The following list of arguments apply to Windows shim logger binaries in this repo:

Name Required Description
log-file-dir No Only supported in Windows. Will be the path where shim logger's log files are written. By default it is \ProgramData\Amazon\ECS\log\shim-logger
proxy-variable No Only supported in Windows. The proxy variable will set the HTTP_PROXY and HTTPS_PROXY environment variables.

Additional log driver options

Amazon CloudWatch Logs

The following additional arguments are supported for the awslogs shim logger binary, which can be used to send container logs to Amazon CloudWatch Logs.

Name Required Description
awslogs-group Yes The log group in which the log stream for the container will be created.
awslogs-stream Yes The log stream name to stream container logs to.
awslogs-region Yes The region name in which the log group and log stream needs to be created in.
awslogs-credentials-endpoint Yes The endpoint from which credentials are retrieved from to connect to Amazon CloudWatch Logs.
awslogs-create-group No Set to false by default. If the provided log group name does not exist and this value is set to false, the binary will directly exit with an error
awslogs-create-stream No Set to true by default. The log stream will always be created unless this value specified to false explicitly. If the value is false and the log stream does not exist, logging will fail silently instead of failing the container task.
awslogs-multiline-pattern No Matches the behavior of the awslogs Docker log driver.
awslogs-datetime-format No Matches the behavior of the awslogs Docker log driver
awslogs-endpoint No Matches the behavior of the awslogs Docker log driver

Splunk

The following additional arguments are supported for the splunk shim logger binary, which can be used to send container logs to splunk. You can find a description of what these parameters are used for here.

Name Required
splunk-token Yes
splunk-url Yes
splunk-source No
splunk-sourcetype No
splunk-index No
splunk-capath No
splunk-caname No
splunk-insecureskipverify No
splunk-format No
splunk-verify-connection No
splunk-gzip No
splunk-gzip-level No
splunk-tag No
labels No
env No
env-regex No

Fluentd

The following additional arguments are supported for the fluentd shim logger binary, which can be used to send container logs to Fluentd. Note that all of these are optional arguments.

Name Required Description
fluentd-address No The address of the Fluentd server to connect to. By default, the localhost:24224 address is used.
fluentd-async-connect No Specifies if the logger connects to Fluentd in background. Defaults to false.
fluentd-sub-second-precision No Generates logs in nanoseconds. Defaults to true. Note that this is in contrast to the default behaviour of fluentd log driver where it defaults to false.
fluentd-buffer-limit No Sets the number of events buffered on the memory in bytes. Defaults to 1048576 (1MB).
fluentd-tag No Specifies the tag used for log messages. Defaults to the first 12 characters of container ID.

License

This project is licensed under the Apache-2.0 License.

shim-loggers-for-containerd's People

Contributors

aaithal avatar akshat-kmr avatar amazon-auto avatar austinvazquez avatar binsquare avatar choihca avatar dependabot[bot] avatar dharmadheeraj avatar garmikea avatar haddscot avatar josevillalta avatar kzys avatar meghnaprabhu avatar ningziwen avatar pettitwesley avatar samjkon avatar singholt avatar xia-wu avatar xjhe avatar xxx0624 avatar zhonghui12 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

shim-loggers-for-containerd's Issues

Verify logs in Splunk local in e2e tests

Draft code which can get a long xml but without the log sent by e2e tests. Need to investigate how to search the results. Opened the issue in splunk repo: splunk/docker-splunk#625

func validateTestLogsInSplunk(url string, token string, testLog string) {
	// Use REST API to retrieve the logs. https://docs.splunk.com/Documentation/Splunk/9.1.1/RESTREF/RESTsearch#search.2Fjobs
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	searchQuery := "search *" // Get the latest of all the log events.
	req, err := http.NewRequest("POST", fmt.Sprintf("%s/services/search/jobs", url), bytes.NewBufferString(searchQuery))
	gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Authorization", fmt.Sprintf("Splunk %s", token)) // https://docs.splunk.com/Documentation/Splunk/9.1.1/Security/UseAuthTokens
	resp, err := client.Do(req)
	gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
	fmt.Println(string(body))
}

The multiline pattern of awslogs shim logger cannot log the last matched line in e2e tests

During my test against awslogs shim logger, the last matched line cannot be logged when multiline pattern is set.

For example, when the multiline pattern is ^INFO, and the log printed by container is

INFO a
INFO b
INFO c

Only INFO a and INFO b can be passed to awslogs.

This may be caused by test set up or the bug of the feature itself.

Need more investigation. Some potential directions to investigate:

  • Try to reproduce with Nerdctl by specifying the shim logger binary path.
  • The shim logger depends on the log drivers in Moby. So we can try to reproduce by Docker with its native awslogs driver.
  • The logic here seems processing event first with buffer and then append to the buffer. So it is possible that the last line's content is attached to the buffer finally but does not have chance to be processed.
  • The current awslogs test infra uses AWS local stack , so may have feature gaps.

Flaky unit test: Order is not guaranteed when iterating over a map

Unit test is failing, log message here:

2023-07-12T21:57:19.9885430Z     --- FAIL: TestGetDockerConfigs/NoError (0.01s)
2023-07-12T21:57:19.9895872Z         args_test.go:278: assertion failed: env0=envValue0 (testContainerEnvSlice[i] string) != env1=envValue1 (args.ContainerEnv[i] string)
2023-07-12T21:57:19.9959246Z FAIL

This is happening because the implementation of ContainerEnv is converting a map to a slice which does not guarantee ordering: https://github.com/aws/amazon-ecs-shim-loggers-for-containerd/blob/e1ce0e61f9b35a41eb7112b9b5862fb8c79d600b/args.go#L97

While for the unit test, it is ordered: testContainerEnv = "{\"env0\":\"envValue0\",\"env1\":\"envValue1\"}"

https://github.com/aws/amazon-ecs-shim-loggers-for-containerd/blob/e1ce0e61f9b35a41eb7112b9b5862fb8c79d600b/args_test.go#L40


Since the implementation does not care about the order, we should rewrite the test to either change the loop to make a map instead and check the contents match.

Supporting Long Log Lines in Fargate PV 1.4

Supporting Long Log Lines in Fargate PV 1.4

Background

Related Issues

How Container Logs are processed with FireLens

When the fluentd log driver is used (ex: Amazon ECS FireLens), the following is the data-flow:

App container stdout/stderr => container runtime (containerd) => fluentd log driver (shim logger package) => unix socket 
  => Fluent Bit Forward input

The key take-away here is that logs do not go straight to Fluent Bit, they pass through the container runtime and log driver first.

Multiline Log Use Case: Long Log Lines

The other major multiline logging use case is long log lines. Monitoring is critical to modern containerized applications, and we have seen many customers that produce very large and verbose log events. Structured logging, where logs are generated by the app with a set schema/format (usually JSON) is also very common. Many customers, will log huge amounts of information in a single JSON log event- 1 MB log events are not unheard of.

These large logs are emitted by the application in a single line of code/single print statement. However, the container runtime must process them, and most container runtimes, including Docker and Containerd, will split log lines when they are greater than 16KB. In the case of log files, each 16KB chunk of a split log is written to a new log line. In the case of the Fluentd Docker Log driver, each 16KB chunk of data is a separate event.

For the Fluentd Docker Log Driver, a key will be set to note that the message is partial. Below are real split docker logs. A large log line was sent to both stdout and stderr, which are separate pipes, so each is split and creates a series of messages. Notice that stderr and stdout have different values for partial_id.

This is because stderr and stdout

{"source": "stdout", "log": "...", "partial_message": "true", "partial_id": "dc37eb08b4242c41757d4cd995d983d1cdda4589193755a22fcf47a638317da0", "partial_ordinal": "1", "partial_last": "false", "container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig"}]
{"container_name": "/hopeful_taussig", "source": "stderr", "log": "...", "partial_message": "true", "partial_id": "ecccce95711776e6a06d631af8e9227686446814eba7a87cb59b36bbaaad8b58", "partial_ordinal": "1", "partial_last": "false", "container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2"}]
{"partial_last": "false", "container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig", "source": "stdout", "log": "...", "partial_message": "true", "partial_id": "dc37eb08b4242c41757d4cd995d983d1cdda4589193755a22fcf47a638317da0", "partial_ordinal": "2"}]
{"log": "...", "partial_message": "true", "partial_id": "dc37eb08b4242c41757d4cd995d983d1cdda4589193755a22fcf47a638317da0", "partial_ordinal": "3", "partial_last": "false", "container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig", "source": "stdout"}]
{"source": "stderr", "log": "...", "partial_message": "true", "partial_id": "ecccce95711776e6a06d631af8e9227686446814eba7a87cb59b36bbaaad8b58", "partial_ordinal": "2", "partial_last": "false", "container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig"}]
{"partial_id": "ecccce95711776e6a06d631af8e9227686446814eba7a87cb59b36bbaaad8b58", "partial_ordinal": "3", "partial_last": "false", "container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig", "source": "stderr", "log": "...", "partial_message": "true"}]
{"container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig", "source": "stdout", "log": "...", "partial_message": "true", "partial_id": "dc37eb08b4242c41757d4cd995d983d1cdda4589193755a22fcf47a638317da0", "partial_ordinal": "4", "partial_last": "false"}]
{"partial_last": "false", "container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig", "source": "stderr", "log": "...", "partial_message": "true", "partial_id": "ecccce95711776e6a06d631af8e9227686446814eba7a87cb59b36bbaaad8b58", "partial_ordinal": "4"}]
{"container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig", "source": "stdout", "log": "...", "partial_message": "true", "partial_id": "dc37eb08b4242c41757d4cd995d983d1cdda4589193755a22fcf47a638317da0", "partial_ordinal": "5", "partial_last": "true"}]
{"log": "...", "partial_message": "true", "partial_id": "ecccce95711776e6a06d631af8e9227686446814eba7a87cb59b36bbaaad8b58", "partial_ordinal": "5", "partial_last": "true", "container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig", "source": "stderr"}]

The following partial metadata fields should be present in split container logs:

  • partial_message: boolean to signal if the message is partial or not.
  • partial_id: all parts of a split message get the same unique ID
  • partial_ordinal: counts up from 1, ordering the parts of the split message.
  • partial_last: is this the last split message or not.

AWS for Fluent Bit issue: aws/aws-for-fluent-bit#25

Problem Statement

In Fargate PV 1.4, which uses this containerd shim logger package, long log messages are currenly split, but the partial metadata keys are not added to the outputted logs.

These partial metadata keys are standard and customers expect them to be added. PV 1.3 correctly adds these partial metadata keys.

Implementation

Currently, the shim logger package does split long log lines and does track whether messages are partial or not: https://github.com/aws/amazon-ecs-shim-loggers-for-containerd/blob/master/logger/common.go#L234

However, the shim logger code does not properly set the partial metadata attributes in the message structure: https://github.com/moby/moby/blob/master/daemon/logger/copier.go#L114

Implementation will set the partial metadata fields and generate partial IDs.

Testing Plan

Unit Test Cases

TODO

Manual Test Cases

Created a test logger container which outputs 10 long log lines of a configurable length, 5 to stdout and 5 to stderr.

The logs can be sent to a local Fluent Bit and outputted to a file after Fluent Bit re-joins the split messages.

Created a validation script to read the outputted file and validate that all log lines were properly re-joined.

TODO: add scripts and results

Enable linting on Windows platform in GitHub Actions CI

During #41, I found the Windows platform test and linting was not being ran. I was able to get test work, but linting was more effort and I did not want to block addressing other CI issues.

This task would be to enable linting on the Windows platform and address any issues found.

Update GitHub actions to build against Go1.18 and 1.19

Mainly my goal is to update the build to use a more modern version of the compiler. It looks like Go is offering support for past two versions available. Although I think an argument could be made for building against Go 1.16 and 1.17 as well for folks who haven't upgraded their toolchain yet.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.