# This ConfigMap is used to ingest logs against new resources like # "k8s_container" and "k8s_node" when $LOGGING_STACKDRIVER_RESOURCE_TYPES is set # to "new". # When $LOGGING_STACKDRIVER_RESOURCE_TYPES is set to "old", the ConfigMap in # fluentd-gcp-configmap-old.yaml will be used for ingesting logs against old # resources like "gke_container" and "gce_instance". kind: ConfigMap apiVersion: v1 data: containers.input.conf: |- # This configuration file for Fluentd is used # to watch changes to Docker log files that live in the # directory /var/lib/docker/containers/ and are symbolically # linked to from the /var/log/containers directory using names that capture the # pod name and container name. These logs are then submitted to # Google Cloud Logging which assumes the installation of the cloud-logging plug-in. # # Example # ======= # A line in the Docker log file might look like this JSON: # # {"log":"2014/09/25 21:15:03 Got request with path wombat\\n", # "stream":"stderr", # "time":"2014-09-25T21:15:03.499185026Z"} # # The original tag is derived from the log file's location. # For example a Docker container's logs might be in the directory: # /var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b # and in the file: # 997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log # where 997599971ee6... is the Docker ID of the running container. # The Kubernetes kubelet makes a symbolic link to this file on the host # machine in the /var/log/containers directory which includes the pod name, # the namespace name and the Kubernetes container name: # synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log # -> # /var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log # The /var/log directory on the host is mapped to the /var/log directory in the container # running this instance of Fluentd and we end up collecting the file: # /var/log/containers/synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log # This results in the tag: # var.log.containers.synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log # where 'synthetic-logger-0.25lps-pod' is the pod name, 'default' is the # namespace name, 'synth-lgr' is the container name and '997599971ee6..' is # the container ID. # The record reformer is used to extract pod_name, namespace_name and # container_name from the tag and set them in a local_resource_id in the # format of: # 'k8s_container...'. # The reformer also changes the tags to 'stderr' or 'stdout' based on the # value of 'stream'. # local_resource_id is later used by google_cloud plugin to determine the # monitored resource to ingest logs against. # Json Log Example: # {"log":"[info:2016-02-16T16:04:05.930-08:00] Some log text here\n","stream":"stdout","time":"2016-02-17T00:04:05.931087621Z"} # CRI Log Example: # 2016-02-17T00:04:05.931087621Z stdout F [info:2016-02-16T16:04:05.930-08:00] Some log text here @type tail path /var/log/containers/*.log pos_file /var/log/gcp-containers.log.pos # Tags at this point are in the format of: # reform.var.log.containers.__-.log tag reform.* read_from_head true @type multi_format format json time_key time time_format %Y-%m-%dT%H:%M:%S.%NZ format /^(? @type parser format /^(?\w)(? @type record_reformer enable_ruby true # Extract local_resource_id from tag for 'k8s_container' monitored # resource. The format is: # 'k8s_container...'. "logging.googleapis.com/local_resource_id" ${"k8s_container.#{tag_suffix[4].rpartition('.')[0].split('_')[1]}.#{tag_suffix[4].rpartition('.')[0].split('_')[0]}.#{tag_suffix[4].rpartition('.')[0].split('_')[2].rpartition('-')[0]}"} # Rename the field 'log' to a more generic field 'message'. This way the # fluent-plugin-google-cloud knows to flatten the field as textPayload # instead of jsonPayload after extracting 'time', 'severity' and # 'stream' from the record. message ${record['log']} # If 'severity' is not set, assume stderr is ERROR and stdout is INFO. severity ${record['severity'] || if record['stream'] == 'stderr' then 'ERROR' else 'INFO' end} tag ${if record['stream'] == 'stderr' then 'raw.stderr' else 'raw.stdout' end} remove_keys stream,log # Detect exceptions in the log output and forward them as one log entry. @type detect_exceptions remove_tag_prefix raw message message stream "logging.googleapis.com/local_resource_id" multiline_flush_interval 5 max_bytes 500000 max_lines 1000 system.input.conf: |- # Example: # Dec 21 23:17:22 gke-foo-1-1-4b5cbd14-node-4eoj startupscript: Finished running startup script /var/run/google.startup.script @type tail format syslog path /var/log/startupscript.log pos_file /var/log/gcp-startupscript.log.pos tag startupscript # Examples: # time="2016-02-04T06:51:03.053580605Z" level=info msg="GET /containers/json" # time="2016-02-04T07:53:57.505612354Z" level=error msg="HTTP Error" err="No such image: -f" statusCode=404 # TODO(random-liu): Remove this after cri container runtime rolls out. @type tail format /^time="(?