Repository navigation
Conversation
…field parsing - default: append email.cc.address when fortinet.firewall.cc is present; the condition tested fortinet.cc.address, which nothing writes. - utm: stop renaming the email sender into tls.server.issuer; it is already copied to email.sender.address, so remove the raw field. - utm: append recipient to email.to.address as an array instead of renaming it to a string (the following append was unreachable). - default: capture the RFC 5424 header timestamp and use it as @timestamp when the log has no date/time fields. - default: strip units from FortiExtender rsrp, rsrq, signalstrength, sinr and temperature and convert them to numbers; map sinr as float. Add an email filter test line and regenerate expected output. Assisted-by: Claude Code/Claude Opus 5.5
Assisted-by: Claude Code/Claude Opus 5.5
Contributor
✅ Elastic Docs Style Checker (Vale)No issues found on modified lines! The Vale linter checks documentation changes against the Elastic Docs style guide. To use Vale locally or report issues, refer to Elastic style guide for Vale. |
Contributor
|
✅ All changelog entries have the correct PR link. |
Contributor
🚀 Benchmarks reportTo see the full report comment with |
💚 Build Succeeded
|
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues remain for the FortiGate email, timestamp, and cellular-statistics mapping fixes.
No open issues 🎉
What changed in this PR
This PR fixes five field-mapping issues in the Fortinet FortiGate log data stream, correcting email fields, event timestamps, and numeric cellular statistics.
Changes:
- Corrects CC and recipient address arrays and prevents email senders from populating TLS issuer fields.
- Uses RFC 5424 header timestamps when log date/time fields are absent and converts unit-bearing FortiExtender statistics to numbers.
- Updates regression fixtures, documents the
sinrfloat mapping, and bumps the package to1.36.12.
| File | Description |
|---|---|
packages/fortinet_fortigate/manifest.yml |
Bumps the package version to 1.36.12. |
packages/fortinet_fortigate/docs/README.md |
Documents sinr as a float. |
packages/fortinet_fortigate/data_stream/log/fields/fields.yml |
Changes the sinr mapping to float. |
packages/fortinet_fortigate/data_stream/log/elasticsearch/ingest_pipeline/utm.yml |
Fixes recipient arrays and removes the incorrect sender-to-TLS mapping. |
packages/fortinet_fortigate/data_stream/log/elasticsearch/ingest_pipeline/default.yml |
Fixes CC mapping, captures RFC 5424 timestamps, and converts cellular statistics. |
packages/fortinet_fortigate/data_stream/log/_dev/test/pipeline/test-fortinet-7-4.log-expected.json |
Updates expected email fields, timestamps, and numeric statistics. |
packages/fortinet_fortigate/data_stream/log/_dev/test/pipeline/test-fortinet-7-4.log |
Adds an email-filter regression fixture. |
packages/fortinet_fortigate/data_stream/log/_dev/test/pipeline/test-fortinet-6-2.log-expected.json |
Expects numeric FortiExtender statistics. |
packages/fortinet_fortigate/changelog.yml |
Records the email, timestamp, and cellular-statistics fixes. |
Review effort: Balanced
This was referenced Oct 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note: drafted with 🤖 Claude Code/Claude Opus 5.5 under my supervision.
What goes wrong today
Five field-mapping bugs in the
logdata stream. All are silent: no error, no tag, and the existing pipeline tests passed with them in place.email.cc.addressis never set. On email filter logs withcc=, theappendthat fillsemail.cc.addressis gated onctx.fortinet?.cc?.address. The kv script writes every key underfortinet.firewall.*, and nothing writesfortinet.cc.address, so the condition is never true and the CC recipients are not indexed.The email sender is also indexed as a TLS certificate issuer.
utm.ymlappendssender=toemail.sender.address, then an unguardedrenamemoves the same field totls.server.issuer. Every email filter event withsender=gets an email address intls.server.issuer, where TLS dashboards and rules read it.email.to.addressis a string, and the append after it never runs.utm.ymlrenamesrecipient=toemail.to.addressand then appends the same, by then missing, field. ECS definesemail.to.addressas an array.elastic-package test pipelinerejects the string (expected array, found "bob@example.org" (string)), but no test line had arecipient=until this change.RFC 5424 format logs get no
@timestampfrom the log. A FortiGate withset format rfc5424sends nodate=/time=fields. The header timestamp is matched but not captured, and@timestampis only set fromdate+time, so these events keep the time they were read rather than the time they were logged. The package's own test line (test-fortinet-7-4.log, line 75) has no@timestampin its expected output.FortiExtender signal statistics are not searchable. On "Cellular Signal Statistics" (logid
0111046409),rsrp,rsrq,signalstrength,sinrandtemperaturecarry units (rsrp="-89 dBm"), butfields.ymlmaps them asintegerand nothing converts them. Onlogs-*data streams (index.mapping.ignore_malformed: true) the values land in_ignored: kept in_source, but no query or aggregation can use them. Withoutignore_malformedthe document is rejected.One line, two documents
A new email filter test line, built from the FortiOS log reference sample
0508020503with documentation addresses:The RFC 5424 test line (
test-fortinet-7-4.log, line 75):The FortiExtender test line (
test-fortinet-6-2.logline 27, and the same line intest-fortinet-7-4.logline 29):How Log Shape found it
Log Shape, an internal tool I'm building (not public yet), runs a line through the package's own pipeline on Elasticsearch and shows which characters of the line each field came from and which processor moved them. Its coverage audit reports conditions that are never true (or never false) over the package's test lines and grok alternatives that never win, and indexes the resulting documents the way Fleet would.
It started with coverage: over the 214
logtest lines onmain, the audit flagged four of the five bugs.append_email_cc_address_4d235e7f: "the condition needsfortinet.cc.address, which no processor, script or agent template writes and no test config seeds; it was false on all 214 evaluations".utm.yml'sappend_email_sender_address_37ff254candappend_email_to_address_78c2982a: condition never true, because no test line carriedsender=orrecipient=. On a line it wrote by addingsender=, the audit reported "tls.server.issuerholds an email address (alice@example.com): that field never carries one".test-fortinet-7-4.logline 75: "the line carries a timestamp, but@timestampis the ingest time".fortinet.firewall.rsrp=-89 dBmdoes not fit its mapping on 2 test line(s): kept in_sourcebut indexed as_ignored, so no query can find it", and the same forrsrq(-16 dB),signalstrength(92 dBm),sinr(7.0 dB) andtemperature(40 C).The fifth, the string
email.to.address, showed up when the new email filter test line ran. The quotes below are from a run onmain's pipeline (b762a87). Grades:measuredmeans Elasticsearch reported where the value sits in the line;located, Log Shape found it by searching its input field;traced, a processor path the run confirmed.tls.server.issuer. On the new email line, Log Shape placedjdoe@example.com(characters 467–483, thesender=value,measured) inemail.sender.address,tracedthroughappend_email_sender_address_37ff254c, and intls.server.issuer,tracedthroughrename_fortinet_firewall_sender_to_tls_server_issuer_53552963.recipient=valuebob@example.org(measured) inemail.to.address,tracedthroughrename_fortinet_firewall_recipient_to_email_to_address_e1ed6c6b. The next processor,append_email_to_address_78c2982a, was skipped.email.cc.address. Thecc=valuecarol@example.org(measured) reached no field butfortinet.firewall.cc, andappend_email_cc_address_4d235e7fwas skipped. On this branch, the same run tracescarol@example.orgtoemail.cc.addressthroughappend_email_cc_address_4d235e7f, andbob@example.orgtoemail.to.addressthroughappend_email_to_address_78c2982a.165(located) inlog.syslog.priorityanduse2-dmz-fw02(measured) inobserver.name. It placed nothing on2022-11-14T06:54:03Z(characters 7–27), whichgrok_event_original_995e7c66matches as%{TIMESTAMP_ISO8601}without a field name. Bothdateprocessors that set@timestampfrom_temp.timewere skipped. On this branch, Log Shape places2022-11-14T06:54:03Z(characters 7–27,measured) in@timestamp,tracedthroughdate__temp_syslog5424_ts_to_timestamp.test-fortinet-6-2.logline 27, Log Shape placed-89 dBm(characters 429–436,measured) infortinet.firewall.rsrp,traced, with no processor between the kv script and the index, against a declaredinteger. The same holds forsinr(7.0 dB),rsrq(-16 dB),signalstrength(92 dBm) andtemperature(40 C).mainran all 215logtest lines (214 existing, 1 added by this change). Failures: 0 → 0. Of the 214 existing lines, 211 are unchanged. The three that changed are the ones above: line 75 oftest-fortinet-7-4.loggains@timestamp: 2022-11-14T06:54:03.000Z, and on the two FortiExtender lines the five fields become numbers. The header grok's winning patterns are the same on both sides. Nothing regressed.The change
In
default.yml/utm.yml, the five field-mapping fixes. Representative hunks:The rest of the patch (tests, changelog, …) is on the Files tab.
Proposed commit message
What does this PR do?
Fixes the five bugs above in the
logdata stream (default.yml,utm.yml,fields.yml). They were found with the coverage audit and confirmed by running lines through the pipeline; theemail.to.addressone was exposed by the new email filter test line.ctx.fortinet?.firewall?.cc, the field thevaluealready reads.renametotls.server.issueris replaced by aremoveoffortinet.firewall.sender, which keeps the raw field's previous end state (it was not kept, and it is not declared infields.yml).from=still goes toemail.from.address, andemail.sender.addressis correct per ECS (the address responsible for transmitting the message). TLS issuers already come fromscertissuer/issuer/ccertissuer, and I found no FortiOS log type that usessenderfor a certificate issuer.renameis dropped so the existingappendruns, followed by aremoveof the raw field as before._temp.syslog5424_ts(removed with_tempat the end of the pipeline), and a newdateprocessor (ISO8601) sets@timestampfrom it only when_temp.time(fromdate/time) is absent. Logs that havedate/timeare unchanged.sinris reported with a decimal (7.0 dB), so its mapping changes fromintegertofloat.Checklist
changelog.ymlfile (1.36.12).How to test this PR locally
The email filter line under "One line, two documents" is added to
test-fortinet-7-4.log. Its expected document hasemail.cc.address: ["carol@example.org"],email.sender.address: ["jdoe@example.com"],email.to.address: ["bob@example.org"]and notlsobject.Changes to existing expected documents (checked field by field; nothing else moved):
test-fortinet-7-4.log-expected.json@timestamp2022-11-14T06:54:03.000Ztest-fortinet-6-2.log-expected.jsonline 27,test-fortinet-7-4.log-expected.jsonline 29fortinet.firewall.rsrp"-89 dBm"-89fortinet.firewall.rsrq"-16 dB"-16fortinet.firewall.signalstrength"92 dBm"92fortinet.firewall.sinr"7.0 dB"7.0fortinet.firewall.temperature"40 C"40The RFC 5424
@timestampagrees withevent.startfromeventtime(2022-11-14T06:54:02Z) to within the second.The base-versus-head review above agrees: on the added line
+email.cc.address,-tls.server.issuerandemail.to.addressas an array; on existing lines, only the changes in this table.elastic-package checkpasses (with a numeric PR link in the changelog).Related issues
None filed; found with a pipeline coverage audit.
Data flow and coverage
How the data flows (before → after)
Each diagram follows one of this change's own test lines through the pipeline on
mainand on this branch: the processors that touched the values the fix is about, each value as it stood after that step, and what was indexed. Red: wheremaingoes wrong; green: the fixed outcome; heavy blue border: a processor this change adds or edits.fortinet_fortigate/log·test-fortinet-7-4.log#82flowchart LR L["…carol@example.org#quot; sender=#quot;jdoe@example.com#quot; recipient=#quot;bob@example.org…"] subgraph sa["After: this change"] direction LR a0_0["script script_2073fe5f: fortinet.firewall.recipient = #quot;bob@example.org#quot;"] a0_2["remove remove_fortinet_firewall_recipient: fortinet.firewall.recipient"] a0_3["indexed email.to.address = #91;#quot;bob@example.org#quot;#93;"] a0_0 --> a0_2 --> a0_3 a1_0["script script_2073fe5f: fortinet.firewall.cc = #quot;carol@example.org#quot;"] a1_1["append append_email_cc_address_4d235e7f: email.cc.address = #quot;carol@example.org#quot;"] a1_2["indexed email.cc.address = #91;#quot;carol@example.org#quot;#93;"] a1_0 --> a1_1 --> a1_2 end subgraph sb["Before: main"] direction LR b0_0["script script_2073fe5f: fortinet.firewall.recipient = #quot;bob@example.org#quot;"] b0_1["rename rename_fortinet_firewall_recipient_to_email_to_address_e1ed6c6b: email.to.address = #quot;bob@example.org#quot;"] b0_2["indexed email.to.address = #quot;bob@example.org#quot;"] b0_0 --> b0_1 --> b0_2 b1_0["script script_2073fe5f: fortinet.firewall.cc = #quot;carol@example.org#quot;"] b1_1["append append_email_cc_address_4d235e7f: email.cc.address"] b1_2["email.cc.address: not indexed"] b1_0 --> b1_1 --> b1_2 end L --> b0_0 L --> b1_0 L --> a0_0 L --> a1_0 classDef bad fill:#fde2e2,stroke:#c62828,color:#7f1d1d classDef good fill:#e3f6e5,stroke:#2e7d32,color:#14532d classDef fix stroke:#1565c0,stroke-width:3px class b0_2,b1_2 bad class a0_3,a1_2 good class b0_1,b1_1,a0_2,a1_1 fixTest coverage of the change
The changed pipeline region, with how the package's pipeline tests exercise each line on
main→ on this branch (# coverage:lines; counts are test lines).packages/fortinet_fortigate/data_stream/log/elasticsearch/ingest_pipeline/default.ymlpackages/fortinet_fortigate/data_stream/log/elasticsearch/ingest_pipeline/utm.yml