SchemaSmith Documentation

Logging & Exit Codes

Two log streams per run, a color-coded console mirror, automatic numbered backups, and engine-notice routing that differs by platform. Everything a CI pipeline needs from a deploy tool.

By the SchemaSmith Team · Last reviewed

Logging and Exit Codes

Good logs are the difference between a quick diagnosis and a long night.

Framework

All CLI tools use Apache Log4Net. Each tool ships with an embedded Log4Net configuration that is loaded automatically at startup — there's nothing to configure.

Log Files

Each tool writes two log files per run:

Tool Progress log Error log
SchemaQuench SchemaQuench - Progress.log SchemaQuench - Errors.log
SchemaTongs SchemaTongs - Progress.log SchemaTongs - Errors.log
DataTongs DataTongs - Progress.log DataTongs - Errors.log

The progress log receives all informational output: the startup banner, active configuration, per-object progress, and completion status. Everything written to the progress log also appears on the console in real time.

The error log receives only error-level entries (such as SQL execution errors) and does not echo to the console.

Both log files are overwritten at the start of each run. Previous runs are preserved through the backup rotation described below.

Console Output

The console is a live mirror of the progress log, not a separate channel. Watching the console while a quench runs lets you follow startup, per-object progress, and completion in real time without tailing a file. Log4Net colorizes the console stream by level so trouble catches your eye the moment it appears:

Level Console color
InformationalGreen
WarningYellow
ErrorRed

When a script fails, you see a short error summary on the console and in the progress log (red, so it's hard to miss): the failing script path and the engine's error message, along with a Debug Script: pointer when a generated procedure is the source. That's enough to know what failed and where to look.

The full token-expanded SQL the server rejected is written to a separate, re-runnable .sql artifact file rather than dumped into the log stream; the log points you to it with a Resolved SQL written to: or Debug Script: line. That keeps the progress and error logs safe to ship — no expanded secrets, no multi-KB batch dumps — while the artifact stays on the deploy host as your local reproduction tool. See Working a failed deployment to trace one end to end.

On multi-target runs the log stays greppable: every schema-template iteration prefixes its lines with [Schema: <name>], and a many-database fan-out uses [server].[database]. Filter the progress log to one prefix to isolate a single tenant's sequence end to end.

Tip

CI agents that capture stdout get the progress stream for free. If your pipeline step only saves stdout, you still have a readable transcript of successes and error summaries; archive the error log separately to keep the failed-batch detail.

Log File Location

By default, logs are written to the tool's executable directory. Override this with --LogPath:

SchemaQuench --LogPath:C:\Logs
SchemaTongs --LogPath:C:\Logs\schemasmith
DataTongs --LogPath:D:\BuildLogs
SchemaQuench --LogPath:/var/log/schemasmith
SchemaTongs --LogPath:/var/log/schemasmith
DataTongs --LogPath:/var/log/buildlogs

Startup Configuration Dump

Immediately after loading configuration, every tool logs its complete active configuration to the progress log. This includes the tool name and version number, followed by every configuration key and its value (with passwords masked). This makes it straightforward to verify what settings were in effect for any given run.

Any value whose name matches the built-in sensitive-name set — Password, Pwd, Secret, ApiKey, Token, ConnectionString, Credential (case-insensitive, substring match) — is replaced with *** while its name still prints, so you can confirm the setting exists without exposing it. An embedded Password= / Pwd= inside a connection-string value is stripped even when the surrounding name isn't sensitive. All other values are logged as-is.

You can tune what gets scrubbed — add exact names or patterns, or opt a false positive back out — and suppress token logging entirely via the LogHygiene settings block. See Sensitive value masking in the configuration reference.

2026-03-06 09:14:01,234 - SchemaQuench
2026-03-06 09:14:01,235 - Version: 5.2.1.0
2026-03-06 09:14:01,236 - Configuration:
2026-03-06 09:14:01,237 -   Server: sql-prod-01
2026-03-06 09:14:01,238 -   User: schemasmith
2026-03-06 09:14:01,239 -   Password: ***
2026-03-06 09:14:01,240 -   VerboseLogging: false

Log Backup Rotation

When a tool finishes (whether successfully or after an error), it backs up its log files before the process exits:

  1. Determines the log directory (--LogPath value, or the executable directory if not specified).
  2. Creates a numbered subdirectory: <ToolName>.0001. If that directory already exists, it increments: .0002, .0003, and so on.
  3. Copies all files matching <ToolName> - *.log into the new subdirectory.

The base log files in the log directory are not deleted after backup. Each run overwrites the base files and writes a copy into a new numbered subdirectory. This preserves the history of every run while keeping the base files current with the latest.

Example after three SchemaQuench runs:

C:\Tools\
    SchemaQuench - Progress.log      (latest run)
    SchemaQuench - Errors.log        (latest run)
    SchemaQuench.0001\               (first run backup)
    SchemaQuench.0002\               (second run backup)
    SchemaQuench.0003\               (third run backup)

Working a failed deployment

A failed quench leaves two things for you: a log entry telling you what broke, and a .sql artifact file holding the exact SQL that the server rejected. Here's how to move from "deployment failed" to "I know what's wrong and I can fix it."

  1. Find the artifact. Open the progress log (SchemaQuench - Progress.log) and search for Resolved SQL written to: (user scripts and data-delivery merges) or Debug Script: (generated quench SQL). Either line gives you the full path to the artifact file.
    Unable to quench 'Before/01-seed-config.sql': Invalid column name 'Region'.
        Resolved SQL written to: C:\deploy\SchemaQuench - Failed 01-seed-config prod-db.TargetDB.sql
    Artifacts land in the ArtifactPath directory (default: the working directory you ran SchemaQuench from), not the log directory — deliberately, so zipping your logs for a support ticket doesn't sweep up raw SQL that may contain expanded sensitive values.
  2. Open and read it. The artifact is a plain .sql file: a comment header identifying the server, database, schema, and which script failed, followed by every batch the engine sent, separated by GO. The batch SchemaQuench attempted last is marked:
    -- >>> FAILING BATCH (#2) >>>
    ALTER TABLE [dbo].[Orders] ADD [Region] NVARCHAR(50) NOT NULL ...
    GO
    The marker is a best-effort hint — the engine marks the last batch it attempted, usually (but not always) the one that caused the error. The values are real and fully expanded (tokens resolved, connection-string parameters substituted), which is exactly what you need to reproduce the failure.
  3. Reproduce and fix. Open the artifact in your query tool, connect to the same target, and run it. You'll see the exact same error the engine returned during deployment. Work the fix there — iterate until it succeeds — then apply the fix back to your schema package.
  4. Recognize the error class. Most deployment failures fall into one of these:
    • Unresolved token. The batch contains a literal {{Token}} instead of the expanded value — a misspelled token, a token out of scope for this script's slot (a {{SchemaName}} token in a product-level script, say), or a token that was never defined.
    • Dependency order. An object references a table, view, or procedure that doesn't exist yet at the point the script runs. SchemaQuench's retry loop resolves many of these across passes — if the same script fails every pass, the dependency may never be created, or it's circular.
    • Permission. The deploy login lacks the right to create or alter the object. Check its rights against the target database and grant what's needed.
    • Delivery constraint. A merge script hit a foreign-key, unique, or check constraint. Look at the values being inserted or the join logic — the delivered data conflicts with existing rows or references a row that doesn't exist.
  5. Attach it safely. To attach the artifact to a support ticket or CI build artifact, turn on ScrubArtifacts: true before re-running: the artifact then redacts sensitive token values and inline connection-string passwords into a shareable variant. See Failure artifacts in the configuration reference.

Generated debug SQL

When SchemaQuench runs one of its generated procedures against your target database, it dumps the exact SQL it sent to a companion .sql file — the same artifact the Debug Script: line points at. Generated procedures cover missing tables and columns, modified tables, indexes, foreign keys, materialized views, indexed views, and the table-JSON parse step. Debug files follow the pattern SchemaQuench - <operation> <server>.<database>.sql:

SchemaQuench - Quench Missing Tables And Columns prod.NW.sql
SchemaQuench - Quench Modified Tables prod.NW.sql
SchemaQuench - Quench Indexes prod.NW.sql
SchemaQuench - Quench Foreign Keys prod.NW.sql
SchemaQuench - Quench Materialized Views prod.NW.sql
SchemaQuench - Quench Indexed Views prod.NW.sql
SchemaQuench - Parse Table Json prod.NW.sql

Each run overwrites the debug files for the operations it actually performed. Operations that don't apply to your platform (indexed views on PostgreSQL, materialized views on MySQL) produce no file. Debug files land in the ArtifactPath directory (default: current working directory) — --LogPath controls the progress and error logs, not artifact or debug SQL.

Engine Notices

SchemaSmith surfaces the database engine's informational output — notices, prints, and server-side status messages — into the progress log so you can see what the engine is telling you. The wiring differs per platform because each driver exposes that stream differently.

PRINT output and severity-10-or-lower errors arrive through the InfoMessage event. By default SchemaSmith promotes only severity-above-10 errors and RAISERROR ... WITH STATE 100 notifications to the progress log; set VerboseLogging: true to include every PRINT and informational message.

RAISE NOTICE and RAISE WARNING output arrives through the Npgsql Notice event and lands in the progress log. SchemaSmith filters out the "... does not exist, skipping" and "... already exists, skipping" notices that DROP ... IF EXISTS and CREATE ... IF NOT EXISTS produce during normal runs, so your log stays readable.

The MySQL connector doesn't fire info-message events for long-running stored procedures, so SchemaSmith uses a table-based status channel. A SchemaSmith_StatusMessages table in the target database (created automatically during kindling) holds per-session progress rows; the generated quench procedures INSERT into it as they work, and a background poller on a separate connection reads the new rows every 200ms and writes them to the progress log. SessionId is scoped to CONNECTION_ID() so concurrent runs don't cross-talk, and the monitor deletes its rows on shutdown. There's no VerboseLogging dial on MySQL — what you see is whatever the procedures chose to publish.

Note

VerboseLogging is a SchemaQuench setting and applies only to SQL Server's InfoMessage stream. The PostgreSQL and MySQL paths already behave the way VerboseLogging: true behaves on SQL Server — SchemaSmith surfaces every engine-side notice (PostgreSQL) or procedure-emitted status message (MySQL) by default.

Exit Codes

Code Condition Recommended action
0 Normal completion None — the operation succeeded.
2 One or more database quenches failed (SchemaQuench only) Check the progress and error logs for details on which databases failed and why. Fix the failing scripts and re-run.
3 Unhandled exception An unexpected error occurred. The exception is logged to both the progress and error logs before exit. Report the error with the log contents if the cause isn't obvious.
4 Log backup failure The tool completed its main work but couldn't back up the log files. Check directory permissions and disk space in the log directory. The base log files may still be readable even though the backup failed.

Pre-flight checks that fail before any deployment — a --TestConnection failure, a server below the product's MinimumVersion floor, or a --PreviewTargets run that finds a required template with zero targets — also exit 2, so a readiness gate in CI can treat any non-zero exit the same way.