Skip to content

Improve and customize logging output - #139

Open
AF-cgi wants to merge 3 commits into
swhitty:mainfrom
AF-cgi:feature/log-handler
Open

Improve and customize logging output#139
AF-cgi wants to merge 3 commits into
swhitty:mainfrom
AF-cgi:feature/log-handler

Conversation

@AF-cgi

@AF-cgi AF-cgi commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Add Log.handler to control diagnostic output

Motivation

SwiftDraw writes diagnostics straight to the standard streams with print() — 27 call sites, 20 in the library and 7 in the command line tool. None of them can be silenced or redirected, so an embedding tool gets [parsing error] on standard error for every element that fails to parse and Alignment: / Created: on standard output, mixed into its own output. Issue #59 is an example of this surfacing where it was not wanted.

What this does

Adds SwiftDraw.Log, a handler every message passes through:

Log.handler = { level, message in   // .info, .warning, .error
    logger.log(level: ..., "\(message)")
}

Log.handler = Log.silent

The command line tool gains --quiet, which installs Log.standardStreams(minimumLevel: .error).

Three commits: the handler, then the library call sites, then the tool.

Impact

  • Output is unchanged by default. I built main in a worktree and diffed both binaries across five scenarios (gradient and filter warnings, --insets auto, malformed SVG, stroke-width override, missing file). stdout, stderr and the generated files are byte identical. The only difference in the tool's output is the new --quiet line in the help.
  • Additive only. Nothing removed or renamed; Configuration.logLevel has a default value.
  • No new dependencies. The handler is a plain closure, so bridging to swift-log or OSLog is a three-line switch on the embedder's side. Verified compiling against this branch in Swift 6 language mode with only import SwiftDraw.
  • --quiet silences warnings, Created:, the alignment insets and the help dump that followed a failed conversion. Failures still go to stderr and the exit code is unchanged.

18 new tests, suite green at 243.

Notes

Log lives in the SwiftDraw module rather than SwiftDrawDOM. Declaring it in DOM and re-exporting it does not work for clients: DOM is not a package product, so MemberImportVisibility hides every member and the import it suggests is unavailable. The storage is a package type in DOM that both modules emit through, with SwiftDraw.Log as the public facade.

Only --quiet is added, not --verbose — everything is already reported by default, so a verbose flag would have nothing to enable.

Two things I could easily change if you prefer: Log.info/warning/error are public so the tool needs no package internals, and --quiet also suppresses the SF Symbol Alignment: output, which is arguably program output rather than a diagnostic.

Parsing errors and rendering warnings are currently written straight to
the standard streams, which embedders cannot silence or route into their
own logging system.

Introduce LogSink, a package level sink holding the handler, and expose
it as SwiftDraw.Log. The default handler writes info messages to standard
output and everything else to standard error, so the output is unchanged.

Log lives in the SwiftDraw module rather than being re-exported from
SwiftDrawDOM: the DOM module is not a package product, so members of a
type declared there are unreachable for clients building with
MemberImportVisibility.

Call sites still use print() and are migrated separately.
@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.91045% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.22%. Comparing base (cf234e7) to head (3c9bdda).

Files with missing lines Patch % Lines
SwiftDraw/Sources/Log.swift 66.66% 9 Missing ⚠️
SwiftDraw/Sources/Renderer/Renderer.SFSymbol.swift 50.00% 3 Missing ⚠️
DOM/Sources/Parser.XML.Element.swift 75.00% 2 Missing ⚠️
...wiftDraw/Sources/Formatter/XML.Formatter.SVG.swift 0.00% 2 Missing ⚠️
...Sources/LayerTree/LayerTree.CommandGenerator.swift 33.33% 2 Missing ⚠️
...ources/CommandLine/CommandLine.Configuration.swift 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #139      +/-   ##
==========================================
+ Coverage   88.91%   89.22%   +0.31%     
==========================================
  Files         166      170       +4     
  Lines       13466    13715     +249     
==========================================
+ Hits        11973    12237     +264     
+ Misses       1493     1478      -15     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

AF-cgi added 2 commits August 27, 2026 11:17
Replace every print() in SwiftDraw and SwiftDrawDOM with LogSink, so
parsing errors, rendering warnings and the SF Symbol alignment insets
reach Log.handler.

Levels follow the existing streams: alignment insets are info and keep
going to standard output, unsupported content is a warning and parsing
and encoding failures are errors, both on standard error. The Warning:
prefix now comes from the handler rather than the call site, so it is
not duplicated when messages are routed into another logging system.
Output of the command line tool is unchanged.

Parsing error messages move into makeParsingErrorMessage so they can be
tested without replacing the process wide handler. Tests that do replace
it are collected in a single serialized suite, since suites otherwise
run in parallel and overwrite each other's handler.

The test covering the renderer warning is guarded by canImport(CoreGraphics):
without it SVG.init(dom:options:) records the size and generates no commands,
so there is no warning to observe.

The command line tool still prints directly and is migrated separately.
Route the messages of the command line tool through the log handler and
add --quiet, which installs a handler reporting failures only. Warnings,
the alignment insets, the Created line and the help printed after a
conversion failure are suppressed; failures keep going to standard error
and the exit code is unchanged.

Only --quiet is added, not --verbose: everything is already reported by
default, so a verbose flag would have nothing to enable.

Log.info, Log.warning and Log.error become public so the tool, the first
client of the handler outside the library, needs no package internals.

--quiet is parsed as part of the configuration, so it is only in effect
once the arguments are valid. A usage error is reported either way.
@AF-cgi
AF-cgi force-pushed the feature/log-handler branch from d6b50d7 to 3c9bdda Compare August 27, 2026 09: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.

1 participant