CI Integration¶
Sawmill can gate your CI pipeline on log quality. Use --check to
exit non-zero when unwaived messages exceed a severity threshold.
Check mode¶
$ sawmill build.log --check
In check mode, sawmill:
Parses the log file using the auto-detected (or
--plugin) plugin.Loads waivers from
.sawmill/waivers.toml(or--waivers).Counts unwaived messages at or above the failure threshold.
Exits with code 1 if any are found, 0 otherwise.
Failure threshold¶
--fail-on sets the minimum severity that causes a failure:
$ sawmill build.log --check --fail-on warning
If --fail-on is omitted, the default threshold is the second-lowest
severity level from the plugin. For a plugin with levels
note (0) / warning (1) / error (2) / fatal (3), the default is
warning (level 1) — meaning notes pass, but warnings and above fail.
Waivers in CI¶
Waived messages are excluded from the failure count:
$ sawmill build.log --check --waivers .sawmill/waivers.toml
If --waivers is not specified, sawmill auto-discovers
.sawmill/waivers.toml (or sawmill/waivers.toml) in the current
directory.
See Waivers for the waiver file format.
Suppressions do NOT affect CI¶
Suppressions are display-only. If you combine --suppress or
--suppress-id with --check, sawmill emits a warning to stderr:
Warning: --suppress/--suppress-id affects display only, not CI pass/fail.
Use --waivers for CI acceptance.
Suppressed messages are still counted toward CI pass/fail. Use waivers to formally accept messages.
JSON reports¶
--report writes a JSON summary to a file:
$ sawmill build.log --check --report report.json
The report structure:
{
"metadata": {
"log_file": "build.log",
"plugin": "vivado",
"timestamp": "2026-01-15T10:30:00+00:00",
"fail_on_level": 1
},
"exit_code": 0,
"summary": {
"total": 100,
"suppressed": 5,
"waived": 10,
"by_severity": {"error": 3, "warning": 20, "note": 77},
"waived_by_severity": {"error": 1, "warning": 5, "note": 4}
},
"issues": [
{
"message_id": "Vivado 12-3523",
"severity": "warning",
"content": "Attempt to change...",
"line": 42,
"raw_text": "WARNING: [Vivado 12-3523] ..."
}
],
"waived": [
{
"message_id": "Synth 8-6157",
"severity": "warning",
"content": "...",
"line": 100,
"waiver_message_id": "Synth 8-6157",
"waiver_reason": "Expected in this design"
}
],
"suppressed": [
{
"message_id": "Common 17-55",
"severity": "note",
"content": "...",
"line": 5,
"raw_text": "INFO: [Common 17-55] ..."
}
],
"unused_waivers": [
{
"message_id": "DRC RTSTAT-10",
"reason": "No longer triggered"
}
]
}
Auditing¶
Show waived messages in the output:
$ sawmill build.log --show-waived
Report unused waivers (stale waivers that no longer match any messages):
$ sawmill build.log --report-unused
CI pipeline examples¶
GitHub Actions¶
- name: Check log quality
run: |
pip install sawmill sawmill-plugin-vivado
sawmill build.log --check --fail-on warning --report report.json
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: sawmill-report
path: report.json
GitLab CI¶
check_logs:
script:
- pip install sawmill sawmill-plugin-vivado
- sawmill build.log --check --fail-on warning --report report.json
artifacts:
when: always
paths:
- report.json
Makefile¶
check-logs:
sawmill build.log --check --fail-on warning --report report.json