Skip to content

feat: S14.09 per-message structured data (SolidSyslog_LogWithSd) (#560)#561

Merged
DavidCozens merged 4 commits into
mainfrom
feat/s14-09-log-with-sd
Jun 6, 2026
Merged

feat: S14.09 per-message structured data (SolidSyslog_LogWithSd) (#560)#561
DavidCozens merged 4 commits into
mainfrom
feat/s14-09-log-with-sd

Conversation

@DavidCozens

@DavidCozens DavidCozens commented Jun 6, 2026

Copy link
Copy Markdown
Owner

Closes #560.

The per-message-attachment wave of E14 — caller-built SD-ELEMENTs on individual Log calls, combined with the per-instance base set. The authoring foundation (S14.01–08) has landed; this delivers the headline feature.

API

SolidSyslog_LogWithSd(handle, message, sd, sdCount)sd is an array of SolidSyslogStructuredData* (same type as SolidSyslogConfig.Sd[]). SolidSyslog_Log(h, m) is exactly LogWithSd(h, m, NULL, 0). SolidSyslogMessage is unchanged (per-message SD is a call argument, not message state).

Behaviour

  • Ordering: per-instance (config) SDs first, then the per-message array — both into the one shared SolidSyslogSdElement; NILVALUE only when neither writes.
  • Synchronous: formatting happens in-call, so the caller's SD objects need only live across the call.
  • Robust to caller input: a NULL array with nonzero count is reported (SOLIDSYSLOG_ERROR_LOG_INCONSISTENT_SD, BAD_ARGUMENT) and treated as zero; a NULL element inside the array is skipped. Either way the message still emits — no crash. (The dispatch never null-guarded, and neither array had a NULL-element test; the guard lives in the shared FormatSdElements loop so config arrays are covered too.)

Implementation note

Log and LogWithSd both delegate to a static SolidSyslog_DoLog rather than Log calling LogWithSd directly — that would give LogWithSd one internal reference and trip MISRA 8.7 (public API, external callers invisible to the analysis set). Keeps the project's zero active 8.7 suppressions (D.014).

Verification

  • debug: 1482 tests. BddTargetTests: 66/66. clang-format clean; cppcheck-MISRA exit 0 (verified against CI's exact --addon=misra command).

Reentrancy (for the S14.10 guide)

A custom SD that carries call-specific data reads it via self at Format time; don't share one such object, mutated, across concurrent Log calls — use a per-call-site instance. Immutable/static custom SDs are unaffected.

Deferred → S14.10 (#549)

Worked custom-SD example, oracle round-trip BDD, and the integrator-guide prose. Closes E14.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added SolidSyslog_LogWithSd() API to attach structured data directly to individual log messages.
    • Introduced new error code for inconsistent structured data validation.
  • Bug Fixes

    • Improved NULL pointer handling in structured data arrays; NULL entries are now safely skipped instead of dereferenced.
  • Documentation

    • Updated API documentation and development notes to reflect per-message structured data support and NULL handling behavior.
  • Tests

    • Added comprehensive test coverage for new per-message structured data functionality and edge cases.

DavidCozens and others added 4 commits June 6, 2026 13:43
)

Add SolidSyslog_LogWithSd(handle, message, sd, sdCount) — attaches caller-built
SD-ELEMENTs to a single Log call. SolidSyslog_Log becomes exactly
LogWithSd(h, m, NULL, 0), so there is one formatting path. SolidSyslogMessage is
unchanged (per-message SD is a call argument).

MessageFormatter_Format gains the per-message array; FormatStructuredData emits
the per-instance (config) SDs first, then the per-message array, into the one
shared SolidSyslogSdElement, with NILVALUE only when neither produces an element
(FormatSdElements helper DRYs the loop). A NULL array with nonzero count is
reported (new SOLIDSYSLOG_ERROR_LOG_INCONSISTENT_SD, BAD_ARGUMENT) and treated as
zero so the message still logs — mirroring the Create-time InstallStructuredData
guard.

Tests: emit, base-before-per-message ordering, empty-per-message keeps the base
set, per-message values escaped (injection-proof, asserted on the raw frame), and
the NULL-with-count guard. Worked example + oracle BDD + guide are S14.10.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Having SolidSyslog_Log call SolidSyslog_LogWithSd gave LogWithSd exactly one
internal reference, which cppcheck-misra flags as 8.7 (external linkage used in
one TU) — the public API is genuinely called only from integrator code the
analysis set can't see. Rather than add the project's first active 8.7
suppression (D.014 retired the last), both public functions now delegate to a
static SolidSyslog_DoLog holding the shared validation/guard/format/buffer body,
matching the file's existing thin-public-over-static-helper pattern. Named DoLog
(not Emit) — 'emit' is already taken in OriginSd for writing one SD piece and is
heavily used in prose, while _Do<Operation> is the established 'real impl behind
the public op' idiom (LwipRawTcpStream_Do*).

Also: CLAUDE.md SolidSyslog.h row documents LogWithSd; misra_suppressions.txt
11.8 line drift renumbered (SolidSyslog.c +6, MessageFormatter.c +9), verified
exit 0 against CI's --addon=misra command.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A NULL element inside an Sd array (per-message or config) dereferenced through
the unguarded SolidSyslogStructuredData_Format dispatch and crashed; nothing
tested it (create-time relied only on the SolidSyslogNullSd convention). Guard
the shared MessageFormatter_FormatSdElements loop so a conditionally-absent
(NULL) SD is skipped and the message still emits — the per-message array is
caller input at the call site and must not crash the library. Tests: NULL
element skipped in both the per-message and config arrays, plus NULL-array-with-
count still emits NILVALUE without crashing (the emit side of the existing
report-only guard test).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ce2fb5b-1f85-4518-92c8-cfe8c100195a

📥 Commits

Reviewing files that changed from the base of the PR and between 492ef56 and afceb4f.

📒 Files selected for processing (10)
  • CLAUDE.md
  • Core/Interface/SolidSyslog.h
  • Core/Interface/SolidSyslogErrors.h
  • Core/Source/SolidSyslog.c
  • Core/Source/SolidSyslogMessageFormatter.c
  • Core/Source/SolidSyslogMessageFormatter.h
  • DEVLOG.md
  • Tests/SolidSyslogMessageFormatterTest.cpp
  • Tests/SolidSyslogTest.cpp
  • misra_suppressions.txt

📝 Walkthrough

Walkthrough

This PR implements SolidSyslog_LogWithSd, a new public C API enabling callers to attach structured data arrays to individual log calls. The implementation adds validation for inconsistent SD pairing, extends the message formatter to handle both base (config) and per-message SD sets in order, and introduces comprehensive test coverage with design documentation.

Changes

Per-Message Structured Data Feature

Layer / File(s) Summary
Public API contracts and interfaces
Core/Interface/SolidSyslog.h, Core/Interface/SolidSyslogErrors.h, Core/Source/SolidSyslogMessageFormatter.h, CLAUDE.md
SolidSyslog_LogWithSd(handle, message, sd[], sdCount) is declared alongside a forward declaration of struct SolidSyslogStructuredData and new error code SOLIDSYSLOG_ERROR_LOG_INCONSISTENT_SD. SolidSyslogMessageFormatter_Format signature updated to accept messageSd and messageSdCount parameters. API reference updated to clarify relationship between SolidSyslog_Log and LogWithSd.
Core logging implementation with validation
Core/Source/SolidSyslog.c, misra_suppressions.txt
SolidSyslog_Log refactored to delegate to new internal SolidSyslog_DoLog helper. Public SolidSyslog_LogWithSd entry point added. Runtime validation rejects inconsistent SD (nonzero count with NULL array) by reporting error and sanitizing count to zero, preventing NULL pointer dereferences. Unified code path threads validated SD through to formatter.
Message formatter integration for dual SD sets
Core/Source/SolidSyslogMessageFormatter.c, Core/Source/SolidSyslogMessageFormatter.h, misra_suppressions.txt
SolidSyslogMessageFormatter_Format accepts per-message SD and forwards to refactored MessageFormatter_FormatStructuredData. Both base (config) and per-message SD sets formatted into single RFC 5424 element in order. New MessageFormatter_FormatSdElements helper safely skips NULL entries in provided SD arrays. NILVALUE emitted only when both SD sets empty.
Test coverage for per-message SD
Tests/SolidSyslogTest.cpp, Tests/SolidSyslogMessageFormatterTest.cpp
Formatter test helper updated with new SD parameters. New SD injector formatter enables escaping validation. Unit tests cover null-element skipping, base+per-message ordering, NILVALUE for null array with nonzero count, preservation of base SD when per-message empty, and escaping of injected SD values. Error-handling test asserts SOLIDSYSLOG_ERROR_LOG_INCONSISTENT_SD reported for inconsistent SD.
Feature design documentation
DEVLOG.md
S14.09 entry records API signature, SD ordering rules (base first, then per-message), NULL handling semantics (inconsistent SD reported and sanitized to zero; NULL elements skipped), reentrancy constraints, internal dispatch naming for MISRA 8.7 compliance, and deferred integrator guide and BDD oracle follow-ups.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant SolidSyslog_LogWithSd
  participant SolidSyslog_DoLog
  participant SolidSyslogMessageFormatter_Format
  participant Formatter
  Caller->>SolidSyslog_LogWithSd: handle, message, sd[], sdCount
  SolidSyslog_LogWithSd->>SolidSyslog_DoLog: forward with sd, sdCount
  SolidSyslog_DoLog->>SolidSyslog_DoLog: validate (sdCount>0 && sd==NULL → error)
  SolidSyslog_DoLog->>SolidSyslogMessageFormatter_Format: handle, message, context, messageSd, messageSdCount
  SolidSyslogMessageFormatter_Format->>Formatter: emit base SD (context->Sd)
  SolidSyslogMessageFormatter_Format->>Formatter: emit per-message SD (messageSd[])
  Formatter-->>SolidSyslog_DoLog: RFC 5424 frame with all SD
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly Related Issues

  • DavidCozens/solid-syslog#64: This PR implements the S14.09 per-message structured-data feature, which is part of the broader E14 epic for caller-built SD-ELEMENT attachment on individual log calls combined with per-instance base sets.

Possibly Related PRs

  • DavidCozens/solid-syslog#502: Both PRs extend the SolidSyslogMessageFormatter_Format pipeline by building on the formatter-context SD refactor to support per-message structured data alongside per-instance base SD sets.

Poem

🐰 Per-message SDs hop into the frame,
Base ones first, then newcomers to claim,
Validation guards against NULL despair,
NULL elements skipped with utmost care,
RFC compliant logs, crisp and fair!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and clearly describes the main feature being added: per-message structured data support via SolidSyslog_LogWithSd, referencing both the feature name and issue number.
Description check ✅ Passed The PR description provides comprehensive coverage of Purpose (linked to #560), Change Description (API shape, behavior, ordering, validation, implementation approach), Test Evidence (1482 tests, 66/66 BDD tests, code quality checks), and Areas Affected (public API, formatter, error codes, tests).
Linked Issues check ✅ Passed All objectives from issue #560 are satisfied: SolidSyslog_LogWithSd API added with correct signature and ordering [#560], per-message SDs as call arguments not message state [#560], config SDs first then per-message into shared element with NILVALUE handling [#560], synchronous formatting with SD object lifetime constraint [#560], NULL array/nonzero count validation and NULL element skipping [#560], threading through formatter implemented [#560], comprehensive unit tests covering all requirements [#560]. Deferred items properly documented for S14.10.
Out of Scope Changes check ✅ Passed All changes are directly aligned with #560 scope: new public API (LogWithSd), messaging formatter extensions for per-message SD threading, error code addition, test coverage, and MISRA suppression updates. Documentation (DEVLOG, CLAUDE.md) records implementation decisions and is on-scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/s14-09-log-with-sd

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1519 passed)
   🚦   build-freertos-host-tdd-plustcp: 100% successful (✔️ 1870 passed)
   🚦   build-linux-clang: 100% successful (✔️ 1453 passed)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1453 passed)
   🚦   integration-linux-openssl: 100% successful (✔️ 16 passed)
   🚦   integration-linux-mbedtls: 100% successful (✔️ 14 passed)
   🚦   integration-windows-openssl: 100% successful (✔️ 16 passed)
   🚦   bdd-linux-syslog-ng: 94% successful (✔️ 48 passed, 🙈 3 skipped)
   🚦   bdd-windows-otel: 88% successful (✔️ 45 passed, 🙈 6 skipped)
   🚦   bdd-freertos-qemu-plustcp: 86% successful (✔️ 44 passed, 🙈 7 skipped)
   🚦   bdd-freertos-qemu-lwip: 86% successful (✔️ 44 passed, 🙈 7 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 1298 passed)
   🚦   build-linux-tunable-override: 100% successful (✔️ 1453 passed)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

@DavidCozens DavidCozens merged commit 65bbf5b into main Jun 6, 2026
27 checks passed
@DavidCozens DavidCozens deleted the feat/s14-09-log-with-sd branch June 6, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

S14.09: Per-message structured data (SolidSyslog_LogWithSd)

1 participant