@@ -8,9 +8,96 @@ import (
88 "context"
99
1010 "github.com/crunchydata/postgres-operator/internal/feature"
11+ "github.com/crunchydata/postgres-operator/internal/naming"
1112 "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
1213)
1314
15+ func EnablePatroniLogging (ctx context.Context ,
16+ inCluster * v1beta1.PostgresCluster ,
17+ outConfig * Config ,
18+ ) {
19+ if feature .Enabled (ctx , feature .OpenTelemetryLogs ) {
20+ directory := naming .PatroniPGDataLogPath
21+
22+ // Keep track of what log records and files have been processed.
23+ // Use a subdirectory of the logs directory to stay within the same failure domain.
24+ //
25+ // https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/-/extension/storage/filestorage#readme
26+ outConfig .Extensions ["file_storage/patroni_logs" ] = map [string ]any {
27+ "directory" : directory + "/receiver" ,
28+ "create_directory" : true ,
29+ "fsync" : true ,
30+ }
31+
32+ // https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/-/receiver/filelogreceiver#readme
33+ outConfig .Receivers ["filelog/patroni_jsonlog" ] = map [string ]any {
34+ // Read the JSON files and keep track of what has been processed.
35+ "include" : []string {directory + "/*.log" },
36+ "storage" : "file_storage/patroni_logs" ,
37+
38+ "operators" : []map [string ]any {
39+ {"type" : "move" , "from" : "body" , "to" : "body.original" },
40+ },
41+ }
42+
43+ // https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/-/processor/transformprocessor#readme
44+ outConfig .Processors ["transform/patroni_logs" ] = map [string ]any {
45+ "log_statements" : []map [string ]any {{
46+ "context" : "log" ,
47+ "statements" : []string {
48+ `set(instrumentation_scope.name, "patroni")` ,
49+
50+ // https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/-/pkg/ottl/ottlfuncs#parsejson
51+ `set(cache, ParseJSON(body["original"]))` ,
52+
53+ // The log severity is in the "levelname" field.
54+ // https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext
55+ `set(severity_text, cache["levelname"])` ,
56+
57+ // Map Patroni (python) "logging levels" to OpenTelemetry severity levels.
58+ //
59+ // https://docs.python.org/3.6/library/logging.html#logging-levels
60+ // https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber
61+ // https://github.com/open-telemetry/opentelemetry-python/blob/v1.29.0/opentelemetry-api/src/opentelemetry/_logs/severity/__init__.py
62+ // https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/-/pkg/ottl/contexts/ottllog#enums
63+ `set(severity_number, SEVERITY_NUMBER_DEBUG) where severity_text == "DEBUG"` ,
64+ `set(severity_number, SEVERITY_NUMBER_INFO) where severity_text == "INFO"` ,
65+ `set(severity_number, SEVERITY_NUMBER_WARN) where severity_text == "WARNING"` ,
66+ `set(severity_number, SEVERITY_NUMBER_ERROR) where severity_text == "ERROR"` ,
67+ `set(severity_number, SEVERITY_NUMBER_FATAL) where severity_text == "CRITICAL"` ,
68+
69+ // Parse the "asctime" field into the record timestamp.
70+ // The format is neither RFC 3339 nor ISO 8601:
71+ //
72+ // The date and time are separated by a single space U+0020,
73+ // followed by a comma U+002C, then milliseconds.
74+ //
75+ // https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/-/pkg/stanza/docs/types/timestamp.md
76+ // https://docs.python.org/3.6/library/logging.html#logging.LogRecord
77+ `set(time, Time(cache["asctime"], "%F %T,%L"))` ,
78+
79+ // Keep the unparsed log record in a standard attribute, and replace
80+ // the log record body with the message field.
81+ //
82+ // https://github.com/open-telemetry/semantic-conventions/blob/v1.29.0/docs/general/logs.md
83+ `set(attributes["log.record.original"], body["original"])` ,
84+ `set(body, cache["message"])` ,
85+ },
86+ }},
87+ }
88+
89+ outConfig .Pipelines ["logs/patroni" ] = Pipeline {
90+ Extensions : []ComponentID {"file_storage/patroni_logs" },
91+ Receivers : []ComponentID {"filelog/patroni_jsonlog" },
92+ Processors : []ComponentID {
93+ "transform/patroni_logs" ,
94+ SubSecondBatchProcessor ,
95+ },
96+ Exporters : []ComponentID {DebugExporter },
97+ }
98+ }
99+ }
100+
14101func EnablePatroniMetrics (ctx context.Context ,
15102 inCluster * v1beta1.PostgresCluster ,
16103 outConfig * Config ,
0 commit comments