/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Fluent Bit * ========== * Copyright (C) 2015-2022 The Fluent Bit Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include /* Creates a parser for Docker */ static struct flb_parser *docker_parser_create(struct flb_config *config) { struct flb_parser *p; p = flb_parser_create("_ml_json_docker", /* parser name */ "json", /* backend type */ NULL, /* regex */ FLB_TRUE, /* skip_empty */ "%Y-%m-%dT%H:%M:%S.%L", /* time format */ "time", /* time key */ NULL, /* time offset */ FLB_TRUE, /* time keep */ FLB_FALSE, /* time strict */ FLB_FALSE, /* no bare keys */ NULL, /* parser types */ 0, /* types len */ NULL, /* decoders */ config); /* Fluent Bit context */ return p; } /* Our first multiline mode: 'docker' */ struct flb_ml_parser *flb_ml_parser_docker(struct flb_config *config) { struct flb_parser *parser; struct flb_ml_parser *mlp; /* Create a Docker parser */ parser = docker_parser_create(config); if (!parser) { return NULL; } /* * Let's explain this multiline mode, then you (the reader) might want * to submit a PR with new built-in modes :) * * Containerized apps under Docker writes logs to stdout/stderr. These streams * (stdout/stderr) are handled by Docker, in most of cases the content is * stored in a .json file in your file system. A message like "hey!" gets into * a JSON map like this: * * {"log": "hey!\n", "stream": "stdout", "time": "2021-02-01T01:40:03.53412Z"} * * By Docker log spec, any 'log' key that "ends with a \n" it's a complete * log record, but Docker also limits the log record size to 16KB, so a long * message that does not fit into 16KB can be split in multiple JSON lines, * the following example use short words to describe the context: * * - original message: 'one, two, three\n' * * Docker log interpretation: * * - {"log": "one, ", "stream": "stdout", "time": "2021-02-01T01:40:03.53413Z"} * - {"log": "two, ", "stream": "stdout", "time": "2021-02-01T01:40:03.53414Z"} * - {"log": "three\n", "stream": "stdout", "time": "2021-02-01T01:40:03.53415Z"} * * So every 'log' key that does not ends with '\n', it's a partial log record * and for logging purposes it needs to be concatenated with further messages * until a final '\n' is found. * * We setup the Multiline mode as follows: * * - Use the type 'FLB_ML_ENDSWITH' to specify that we expect the 'log' * key must ends with a '\n' for complete messages, otherwise it means is * a continuation message. In case a message is not complete just wait until * 500 milliseconds (0.5 second) and flush the buffer. */ mlp = flb_ml_parser_create(config, /* Fluent Bit context */ "docker", /* name */ FLB_ML_ENDSWITH, /* type */ "\n", /* match_str */ FLB_FALSE, /* negate */ FLB_ML_FLUSH_TIMEOUT, /* flush_ms */ "log", /* key_content */ "stream", /* key_group */ NULL, /* key_pattern */ parser, /* parser ctx */ NULL); /* parser name */ if (!mlp) { flb_error("[multiline] could not create 'docker mode'"); return NULL; } return mlp; }