The run card: plan, progress and verdict on every thumbnail run
Requires BSI 5.0.0 or later
Earlier versions print an unstructured log stream, and several log lines changed — see log lines your scripts may grep for below.
Every qseow create-sheet-thumbnails, qscloud create-sheet-thumbnails, qseow remove-sheet-icons and qscloud remove-sheet-icons run prints a run card. Both dry and real runs open with a framed header and a PLAN block before anything is changed. A real run then adds countable progress lines while it works (app 2/3, sheet 4/11) and closes with a RESULT verdict; a dry run instead ends with the per-sheet decision report described on Dry Runs — no RESULT block, since nothing was attempted. The output is plain text through the normal log stream, so it lands unchanged in a file redirected from Windows Task Scheduler, in docker logs, and in CI transcripts. No new options are needed; there is nothing to configure.
On an interactive colour terminal at least 72 characters wide, these runs show the same plan and verdict as a colour board instead — see The Contact Sheet. Redirected and scheduled runs always get the plain card described on this page.
Why it exists
Butler Sheet Icons overwrites sheet thumbnails in place, with no undo. Before the run card, a run announced a version number and started writing: which apps were selected and why, what the exclude and blur rules actually matched, and where the images would go were all discoverable only by watching them happen. A run in which 20 thumbnails were written and a run in which a mistyped tag matched nothing ended identically — silently, both with exit code 0.
The run card answers the three questions a run raises, in order:
| Moment | Question it answers |
|---|---|
| PLAN | What is about to be changed, where, and why those apps? |
| Progress | Is it alive, how far in, and on what? |
| RESULT | What actually changed, and did it work? |
What a run looks like
Sample generated from the real renderer (QSEoW, three apps selected by a tag plus one named directly). Shown with log timestamps disabled — see Log timestamps below.
============================================================
BUTLER SHEET ICONS x.y.z -- QSEoW sheet thumbnails
============================================================
PLAN
server sense.company.com https, no virtual proxy
engine 4747, qrs 4242, schema 12.612.0
api user INTERNAL\sa_api via ./cert/client.pem
logon user COMPANY\bsi_svc
apps 3 1 named by --appid, 3 matched by --qliksensetag "sheet-thumbnails", 1 selected twice
sheet part 2 of 4 -- objects + sheet title
exclude tag "no-thumbnail" (0 sheets), number 1
blur tag "confidential" (2 sheets)
browser chrome (version: recommended), headless, 5s per sheet
images ./img/qseow/<app-id>
uploads to content library "Butler sheet thumbnails"
WILL OVERWRITE existing sheet thumbnails in 3 app(s), 2 of them published
app 1/3 c840670c-7178-4a5e-8c5d-2d3e5b0f9a12
"Sales Discovery" -- 11 sheet(s), published
sheet 1/11 excluded 'Scratch pad' (--exclude-sheet-number)
sheet 2/11 captured 'Overview'
sheet 3/11 blurred 'Board pack' (--blur-sheet-tag)
sheet 4/11 captured 'Revenue by region'
...
uploaded 20 image file(s) to content library "Butler sheet thumbnails"
updated 10 of 11 sheet(s) with new thumbnails
...two more apps...
RESULT ok
apps 3 ok, 0 failed
sheets 25 seen, 22 captured (2 blurred), 3 excluded
thumbnails 22 sheet(s) given new thumbnails in content library "Butler sheet thumbnails"
images kept ./img/qseow 44 file(s), 2.6 MB
elapsed 4m 41s
============================================================Points worth knowing:
- The match counts in the PLAN block include zeroes.
tag "no-thumbnail" (0 sheets)printed before the first write is the cheapest possible "check your spelling" — a mistyped tag used to produce a run byte-identical to one where the option was never passed. Match counts are shown for tag rules on client-managed Qlik Sense; number, title and status rules are listed without counts because they are evaluated per sheet during the run. Qlik Sense Cloud has no sheet tags, so its plans show only number, title and status rules. See Sheet exclusion and Sheet blurring for the rules themselves. - The
WILL OVERWRITEline is the warning there was no room for before. There is no undo for a thumbnail update. On a dry run the same line readsWOULD OVERWRITE. Forqscloud remove-sheet-iconsit readsWILL REMOVE sheet icons and thumbnail media files from N app(s). - Progress is countable. A run that hangs now hangs somewhere nameable. Sheet lines print when a sheet completes — they state facts, not intentions — so a hang is on the sheet after the last printed line: a log ending at
sheet 7/11 captured ...means the run is stuck working on sheet 8 (a log with anapp 2/3line and no sheet lines yet is stuck opening that app or capturing its first sheet). Every sheet line names the option responsible for a non-default decision. - The RESULT block is new. There was previously no success summary at all.
RESULT FAILEDwith1 ok, 1 failedalso appears when some apps failed — the per-app error lines above it carry the details. A selection that matched nothing ends withRESULT FAILEDandapps 0 selected - nothing was done, and the run exits 1 as before. Scope of the guarantee: the PLAN and RESULT blocks render once app processing is reached. A run that aborts before that point — a failed connection test, missing certificates, a missing content library, an invalid option — exits 1 with the header and the error lines but no RESULT block, so a wrapper script should treat exit code 1 as the failure signal and the RESULT line as a summary, not as the only marker. - The
browserline shows the version as requested (for examplerecommendedor a pinned build id). The build actually used is still logged at launch, since resolving it may involve the download cache or the network. See Browser management. - The PLAN block appears after the first few connection lines (certificate check, content library check, tag lookup) because the app selection has to be resolved first — but always before anything is written.
Plain ASCII on purpose
The frame — headings, rules, labels — is deliberately plain ASCII with no colour, so the run card survives legacy Windows consoles, non-UTF-8 code pages, and redirection to files, byte for byte. App and sheet names are your data and are printed exactly as they are, including any non-ASCII characters.
Interaction with BSI_LOG_TIMESTAMPS
Each line goes through the normal log stream, so by default it carries the timestamp-and-level prefix. The blocks line up either way, but the card is easiest to read with the prefix off, which is what the sample above shows:
$env:BSI_LOG_TIMESTAMPS = "false"
butler-sheet-icons.exe qseow create-sheet-thumbnails --host sense.company.com ...BSI_LOG_TIMESTAMPS=false ./butler-sheet-icons qseow create-sheet-thumbnails --host sense.company.com ...In a scheduler that already timestamps every captured line, disabling the built-in prefix avoids double timestamps and keeps the plan and verdict columns aligned. See Timestamps in log output for the full behaviour of the switch.
Log levels
- On a dry run, the plan and the dry-run report are the product of the command, so they are printed even at
--log-level warnorerror. - On a real run, the whole run card — header, PLAN, progress and RESULT — logs at
info. A real run of the four thumbnail commands at--log-level warnstays quiet — choosing a quiet level is respected. (The other commands —browser,doctor,qscloud list-collections— print their header regardless of level, as the oldApp version:line always did.) - At
--log-level verboseand below, the detailed per-sheet lines (sheet id, engine sheet id, description, approved, published, hidden) are still available — they moved there rather than being removed.
When a run stops before the header
Requires BSI 5.4.0 or later
Earlier versions print the error on its own, with no version anywhere in the output.
The header is where a run names its version, and the version is the first thing to include when you report a problem. Some runs never get that far: a required option is missing, an option is misspelled, or a value is not one Butler Sheet Icons accepts. Such a run prints a single version line just before its error, so the version is there exactly when something went wrong. This applies to every command, not only the four that print a run card.
Leaving out a required option, for example:
butler-sheet-icons x.y.z - built yyyy-mm-dd
error: required option '--host <host>' not specified- The line is what
--versionreports, folded onto one line. The downloadable executables include the date they were built, as above. The Docker image runs from source and has no build date, so its line isbutler-sheet-icons x.y.zon its own. - On a terminal, a blank line comes first, separating the failure from the command you typed. When the output goes to a log file, a scheduler or another program, there is no blank line: just the version line and the error.
- It is printed whatever
--log-levelis set to, evenerror. - Nothing else changes. The error text is the same as before, and the run still ends with exit code
1; see Exit codes. - A run that gets as far as its header does not add the line, even if it fails later. Usually the header has shown the version by then. The exception is the
create-sheet-thumbnailsandremove-sheet-iconscommands at--log-level warnorerror, which print no header (see Log levels): when one of those runs fails, its output has no version anywhere, so runbutler-sheet-icons --versionand include what it prints.
When reporting a problem
Copy the version line along with the error. It tells whoever helps you which build produced the message.
Breaking change: log lines that scripts may grep for
Anyone parsing Butler Sheet Icons log output should note:
| Before | Now |
|---|---|
App version: <version> (printed by every command) | The framed header: BUTLER SHEET ICONS <version> -- <job> |
-------------------------------------------------- + About to process app <id> | app 1/3 <id> (dry runs: plan app 1/3 <id>) |
App name: "..." / App is published: ... / Number of sheets in app: N at info | One line: "App name" -- N sheet(s), published (individual lines still at verbose) |
Processing sheet 1: '...', sheet id '...', engine sheet id '...', ... (~230 columns) | sheet 1/11 captured '...' (long form at verbose) |
Excluded sheet: 1: '...' | sheet 1/11 excluded '...' (--exclude-sheet-...) |
Done processing app <id> at info | At verbose; the RESULT block closes the run instead |
Uploading images to Qlik Sense content library: ... / Uploading images in folder: ... (client-managed) | uploaded N image file(s) to content library "..." (details at verbose) |
Uploading images in folder: ... / Uploading file: <name> (Cloud, per file at info) | uploaded thumbnails for N sheet(s) to the app's media library (per-file lines at verbose) |
Number of sheets: N / Using blurred thumbnail for sheet N: ... / Using regular thumbnail for sheet N: ... / Skipping update of sheet N: ... (update step, both platforms) | updated N of M sheet(s) with new thumbnails (per-sheet choices at verbose; the sheet lines above already say blurred) |
Removing icon for sheet N: Name '...', ID ..., description '...' (qscloud remove-sheet-icons, per sheet at info) | sheet 1/9 cleared '...' or sheet 2/9 no icon '...' (no icon currently set) (long form at verbose) |
| nothing (remove-sheet-icons media cleanup was silent at info) | deleted N thumbnail media file(s) from the app media library per app |
| nothing | RESULT ok / RESULT FAILED block closing every real run that reaches app processing (pre-loop aborts exit 1 with error lines and no RESULT — key wrappers on the exit code) |
Exit codes are unchanged: 0 on success, 1 when anything failed or the selection was empty.