diff --git a/apps/landing/public/screenshots/guides/log-parsing-01-attributes.webp b/apps/landing/public/screenshots/guides/log-parsing-01-attributes.webp new file mode 100644 index 0000000000..be271b3386 Binary files /dev/null and b/apps/landing/public/screenshots/guides/log-parsing-01-attributes.webp differ diff --git a/apps/landing/public/screenshots/guides/log-parsing-02-columns.webp b/apps/landing/public/screenshots/guides/log-parsing-02-columns.webp new file mode 100644 index 0000000000..a30e9aede4 Binary files /dev/null and b/apps/landing/public/screenshots/guides/log-parsing-02-columns.webp differ diff --git a/apps/landing/src/lib/guide-highlight.ts b/apps/landing/src/lib/guide-highlight.ts index ceeed20613..8c6d9fc741 100644 --- a/apps/landing/src/lib/guide-highlight.ts +++ b/apps/landing/src/lib/guide-highlight.ts @@ -18,7 +18,8 @@ export type GuideLang = | "json" | "shell" | "python-logging" - | "loguru-output"; + | "loguru-output" + | "otel-debug"; const escape = (s: string) => s.replace(/&/g, "&").replace(//g, ">"); const span = (cls: string, text: string) => `${escape(text)}`; @@ -205,15 +206,32 @@ const loguruOutput = (code: string) => }) .join("\n"); -// Shell commands: the program name, flags and quoted arguments. +// Shell commands: the program name, flags and quoted arguments. Single-quoted +// arguments (awk programs, jq filters) are one string, whatever quotes they hold. const shell = (code: string) => tokenize(code, [ [/#.*/y, (m) => span("comment", m[0])], [/(?<=^|\n|\| )(\s*)([\w.-]+)/y, (m) => escape(m[1]) + span("fn", m[2])], + [/'[^'\n]*'/y, (m) => span("labels", m[0])], [/"[^"\n]*"/y, (m) => span("labels", m[0])], [/(?<=\s)--?[\w-]+/y, (m) => span("value", m[0])], ]); +// The OpenTelemetry Collector's debug exporter output: field and attribute keys +// as names, values as values, the type wrappers (Str, Int) as comments. A value +// that runs over several lines leaves its closing parenthesis to the last one. +const otelDebug = (code: string) => + code + .split("\n") + .map((line) => { + const attr = /^(\s*-> )([\w.]+)(: )(\w+\()(.*?)(\)?)$/.exec(line); + if (attr) return span("comment", attr[1]) + span("name", attr[2]) + escape(attr[3]) + span("comment", attr[4]) + span("value", attr[5]) + span("comment", attr[6]); + const field = /^(\w[\w ]*)(:)(.*)$/.exec(line); + if (field) return span("name", field[1]) + escape(field[2]) + span("value", field[3]); + return escape(line); + }) + .join("\n"); + export const highlight = (code: string, lang: GuideLang) => ({ exposition, @@ -233,4 +251,5 @@ export const highlight = (code: string, lang: GuideLang) => shell, "python-logging": pythonLogging, "loguru-output": loguruOutput, + "otel-debug": otelDebug, })[lang](code); diff --git a/apps/landing/src/pages/guides/_log-parsing/debug.yaml b/apps/landing/src/pages/guides/_log-parsing/debug.yaml new file mode 100644 index 0000000000..d9f1e159fb --- /dev/null +++ b/apps/landing/src/pages/guides/_log-parsing/debug.yaml @@ -0,0 +1,9 @@ +# debug.yaml: print parsed records instead of exporting them +exporters: + debug: + verbosity: detailed + +service: + pipelines: + logs: + exporters: [debug] diff --git a/apps/landing/src/pages/guides/_log-parsing/json.yaml b/apps/landing/src/pages/guides/_log-parsing/json.yaml new file mode 100644 index 0000000000..7211c7efeb --- /dev/null +++ b/apps/landing/src/pages/guides/_log-parsing/json.yaml @@ -0,0 +1,34 @@ +receivers: + file_log/app: + include: [/var/log/app/app.log] + resource: + service.name: app + operators: + - type: json_parser + timestamp: + parse_from: attributes.ts + layout_type: gotime + layout: "2006-01-02T15:04:05Z07:00" + severity: + parse_from: attributes.level + - type: move + from: attributes.msg + to: body + on_error: send_quiet + +processors: + batch: {} + +exporters: + otlp_http/maple: + endpoint: https://ingest.maple.dev + compression: gzip + headers: + x-maple-ingest-key: ${env:MAPLE_INGEST_KEY} + +service: + pipelines: + logs: + receivers: [file_log/app] + processors: [batch] + exporters: [otlp_http/maple] diff --git a/apps/landing/src/pages/guides/_log-parsing/logfmt.yaml b/apps/landing/src/pages/guides/_log-parsing/logfmt.yaml new file mode 100644 index 0000000000..208cacc6ba --- /dev/null +++ b/apps/landing/src/pages/guides/_log-parsing/logfmt.yaml @@ -0,0 +1,30 @@ +receivers: + file_log/worker: + include: [/var/log/worker/worker.log] + resource: + service.name: worker + operators: + - type: key_value_parser + timestamp: + parse_from: attributes.time + layout_type: gotime + layout: "2006-01-02T15:04:05Z07:00" + severity: + parse_from: attributes.level + +processors: + batch: {} + +exporters: + otlp_http/maple: + endpoint: https://ingest.maple.dev + compression: gzip + headers: + x-maple-ingest-key: ${env:MAPLE_INGEST_KEY} + +service: + pipelines: + logs: + receivers: [file_log/worker] + processors: [batch] + exporters: [otlp_http/maple] diff --git a/apps/landing/src/pages/guides/_log-parsing/multiline.yaml b/apps/landing/src/pages/guides/_log-parsing/multiline.yaml new file mode 100644 index 0000000000..4814859351 --- /dev/null +++ b/apps/landing/src/pages/guides/_log-parsing/multiline.yaml @@ -0,0 +1,35 @@ +receivers: + file_log/checkout: + include: [/var/log/checkout/app.log] + resource: + service.name: checkout + # A new entry starts at a line beginning with a date. Other lines, such + # as stack frames, are appended to the entry before them. + multiline: + line_start_pattern: '^\d{4}-\d{2}-\d{2} ' + operators: + - type: regex_parser + regex: '(?s)^(?P