MasterSetupLog
Keeps the dated record of the important user actions of a master setup on the very hidden __log worksheet. It is the master setup copy of LLLog. Each event is one Checking bundle: the bundle title is the SECTION the action belongs to, the entry label carries the timestamp, the action code and a short detail, and the scope carries the outcome. Every bundle is flushed through CheckingOutput.PrintOutput in compact mode, so the sheet grows one line per event and the status and title dropdowns of the output sheet filter the log by outcome and by section.
WHAT ONE LINE SAYS
An entry line reads as the timestamp and the platform, then the procedure that raised the event, then the action code and the detail:
2026-08-26 13:55:45 win-64 excel-16.0 clickAddSheet > add-disease: Measles
The procedure is named by the caller. VBA carries no call stack to read a name from, so a line that names only the action leaves the reader guessing which button wrote it. The name is optional: a caller that passes none writes a line opening at the action code.
THE THREE SECTIONS
The log is read by three sections, and the title of an entry is the section the action belongs to. The writer runs in compact mode, so a section title is written the first time the sheet carries it and never again.
open/close the workbook open, the workbook close, a log restart data input/output every export, every import, the disease comparison master setup lifecycle everything else the user does in the file
An action code no case names lands in master setup lifecycle, so a new logged action reaches the sheet without touching this class. A code that opens with export- or import- lands in data input/output for the same reason.
PROVISIONING
Create(wkb) binds to the __log worksheet of the given workbook and builds it very hidden when the workbook has none, so an older master setup grows its log on its first logged event. Building a sheet wants the workbook structure unprotected, which is the duty of the caller.
ROTATION
LOG_MAX_ENTRIES is read as a row cap. A flush that finds the last written row past the cap clears the sheet and removes the row marker CheckingOutput keeps, so the next render re-initialises the sheet, and the fresh log opens with one info line ("restarted").
TEXT EXPORT
A master setup has no Metadata sheet, so the header of the text export carries the file name, the date, the platform and the count of disease worksheets, then the entries in the order they were written.
FILTER DROPDOWNS
The interactive row hiding of the output sheet wants a Worksheet_Change handler injected through the VBE, and injecting code wants VBE trust, which field machines lack. The worksheet code module is left alone; the dropdowns stay plain validation cells and the filtering is reachable through CheckingOutput.FilterWorksheet.
Version: 1.0 (2026-08-26)
Factory
Create #
create
Create a log store bound to the __log worksheet of a workbook
Signature:
Public Function Create(ByVal wkb As Workbook) As MasterSetupLog
Entry point for creating MasterSetupLog instances.
Binds to the __log worksheet of the given workbook. When the workbook has none, the sheet is appended after the last worksheet and made very hidden, so an older master setup grows its log on first use.
Parameters:
wkb: Workbook. The master setup workbook carrying the log.
Returns: MasterSetupLog. Fully initialised instance.
Throws:
- ProjectError.ObjectNotInitialized When wkb is Nothing.
PublicAccessors
SheetName #
sheet-name
Name of the log worksheet
Signature:
Public Property Get SheetName() As String
Answers the internal sheet name so the Open Log door and the deploy list reach the sheet through the class.
Returns: String. The log worksheet name.
SectionOf #
section-of
The section an action code is logged under
Signature:
Public Function SectionOf(ByVal action As String) As String
The three sections are the whole title vocabulary of the log sheet. The workbook open, the workbook close and a log restart are the session boundaries and read as open/close; every export, every import and the disease comparison move data in or out of the file and read as data input/output; every other action the user takes in the file reads as master setup lifecycle, which is also where an action code named by no case below lands.
Parameters:
action: String. The action code of the event.
Returns: String. One of the three section titles.
MaxEntries #
max-entries
Row cap of the log sheet
Signature:
Public Property Get MaxEntries() As Long
Answers the cap the rotation reads, so a test can seed a row past it without writing ten thousand lines.
Returns: Long. The row cap.
DiseaseSheetCount #
disease-sheet-count
How many disease worksheets the workbook carries
Signature:
Public Property Get DiseaseSheetCount() As Long
A disease worksheet is one whose hidden sheetTag name reads disease, the same reading MasterSetupHelpers.IsMasterDiseaseSheet makes. The count heads the text export.
Returns: Long. The count of disease worksheets.
Logging
LogSuccess #
log-success
Log an action that ended well
Signature:
Public Sub LogSuccess(ByVal action As String, _
Optional ByVal detail As String = vbNullString, _
Optional ByVal source As String = vbNullString)
One method per outcome, each flushing one Checking bundle.
Parameters:
action: String. The action code, written on the entry line.detail: Optional String. Short free text beside the timestamp.source: Optional String. The procedure that raised the event.
LogWarning #
log-warning
Log a refusal or a degraded run
Signature:
Public Sub LogWarning(ByVal action As String, _
Optional ByVal detail As String = vbNullString, _
Optional ByVal source As String = vbNullString)
Parameters:
action: String. The action code, written on the entry line.detail: Optional String. Short free text beside the timestamp.source: Optional String. The procedure that raised the event.
LogFailure #
log-failure
Log an action that failed
Signature:
Public Sub LogFailure(ByVal action As String, _
Optional ByVal detail As String = vbNullString, _
Optional ByVal source As String = vbNullString)
Parameters:
action: String. The action code, written on the entry line.detail: Optional String. Short free text beside the timestamp.source: Optional String. The procedure that raised the event.
LogInfo #
log-info
Log a lifecycle line
Signature:
Public Sub LogInfo(ByVal action As String, _
Optional ByVal detail As String = vbNullString, _
Optional ByVal source As String = vbNullString)
Parameters:
action: String. The action code, written on the entry line.detail: Optional String. Short free text beside the timestamp.source: Optional String. The procedure that raised the event.
Export
ReportLines #
report-lines
The whole log as plain text, one line per element
Signature:
Public Function ReportLines() As BetterArray
Writing the log out as a file a user can send on.
The text a user sends on when something goes wrong, so it stands on its own: the workbook it came from, when and on what platform it was written, how many disease worksheets the file carries, then the log itself in the order it was written. The text is built here so what a file will say can be read without a file being written.
Returns: BetterArray. The lines, lower bound 1.
Throws:
- ProjectError.ObjectNotInitialized When the log has no worksheet.
ExportText #
export-text
Write the whole log out as a plain text file
Signature:
Public Function ExportText(ByVal folderPath As String, _
Optional ByVal baseName As String = vbNullString) As String
The file lands in the given folder as
Parameters:
folderPath: String. The folder taking the file.baseName: String. The file name without its suffix. The workbook name when empty.
Returns: String. The full path of the written file.
Throws:
- ProjectError.ObjectNotInitialized When the log has no worksheet.
- ProjectError.InvalidArgument When no folder is given.
Internal members (not exported)
PublicAccessors
Wksh #
wksh
Retrieve the log worksheet backing this store
Signature:
Public Property Get Wksh() As Worksheet
Properties that expose internal state.
Returns: Worksheet. Reference to the log worksheet.
Wksh #
wksh-set
Define the worksheet that will receive the log
Signature:
Public Property Set Wksh(ByVal sh As Worksheet)
Parameters:
sh: Worksheet. Target worksheet to use.
Internals
ResolveLogSheet #
resolve-log-sheet
Resolve the log worksheet, building it very hidden when absent
Signature:
Private Function ResolveLogSheet(ByVal wkb As Workbook) As Worksheet
Sheet resolution, entry building, and rotation.
The sheet is appended after the last worksheet, because a bare Add puts a new sheet in front of whatever is active. An existing sheet keeps its visibility, so the Open Log door can hold it open across a bind.
Parameters:
wkb: Workbook. The master setup workbook.
Returns: Worksheet. The resolved or newly created worksheet.
IsDiseaseSheet #
is-disease-sheet
Whether a worksheet carries the disease tag
Signature:
Private Function IsDiseaseSheet(ByVal sh As Worksheet) As Boolean
HiddenNames.Create raises on a sheet it cannot bind, and a sheet with no tag answers an empty string; both read as a plain worksheet.
Parameters:
sh: Worksheet. The worksheet to read.
Returns: Boolean. True when the sheetTag name reads disease.
AppendHeadingTo #
append-heading-to
The first block of the report: which workbook, when, on what
Signature:
Private Sub AppendHeadingTo(ByVal lines As BetterArray, ByVal sh As Worksheet)
A master setup has no Metadata worksheet, so the header says what a reader of the file wants to know first: the file, the date and the platform of the export, where the file is saved and how many disease worksheets it carries.
Parameters:
lines: BetterArray. The lines built so far.sh: Worksheet. The log worksheet.
AppendEntriesTo #
append-entries-to
Every row of the log sheet, into the report
Signature:
Private Sub AppendEntriesTo(ByVal lines As BetterArray, ByVal sh As Worksheet)
A row carrying the title alone opens a section and reads as a heading in brackets; every other written row is one entry, and it reads as the timestamp, the outcome in brackets, then the action and the detail. Blank rows are dropped, because CheckingOutput lays them out for the eye and they say nothing.
Parameters:
lines: BetterArray. The lines built so far.sh: Worksheet. The log worksheet.
PlainOutcome #
plain-outcome
The outcome word of a row, without the picture in front of it
Signature:
Private Function PlainOutcome(ByVal text As String) As String
Checking paints an outcome with a symbol before the word, and that symbol is what the sheet shows. Print # writes one byte per character, so every one of those symbols reaches the file as a single stray mark. The word alone is what the file wants. A section title carries no symbol and comes back untouched: only a first character outside plain text is taken off.
Parameters:
text: String. The cell value, already trimmed.
Returns: String. The word alone.
CellText #
cell-text
One cell as text, with an error value reading as empty
Signature:
Private Function CellText(ByVal cellValue As Variant) As String
A cell holding #N/A or #REF! raises 13 on CStr, and one such cell must keep the export of everything else alive.
Parameters:
cellValue: Variant. The value read from a cell.
Returns: String. The value as text, or an empty string when it is an error.
WriteEntry #
write-entry
Rotate when the cap is passed, then flush one dated entry
Signature:
Private Sub WriteEntry(ByVal action As String, ByVal detail As String, _
ByVal scope As Byte, _
Optional ByVal source As String = vbNullString)
Parameters:
action: String. The action code, written on the entry line.detail: String. Short free text beside the timestamp.scope: Byte. CheckingScope value carrying the outcome.source: String. The procedure that raised the event. May be empty.
Throws:
- ProjectError.InvalidArgument When the action code is empty.
FlushEntry #
flush-entry
Build one Checking bundle and flush it through the writer
Signature:
Private Sub FlushEntry(ByVal action As String, ByVal detail As String, _
ByVal scope As Byte, _
Optional ByVal source As String = vbNullString)
The bundle title is the section of the action, so the sheet carries three titles. The bundle carries one key, so the key uniqueness of Checking binds inside the bundle and every event stays a plain append.
Parameters:
action: String. The action code, written on the entry line.detail: String. Short free text beside the timestamp.scope: Byte. CheckingScope value carrying the outcome.source: String. The procedure that raised the event. May be empty.
EntryLabel #
entry-label
Compose the dated label of one entry
Signature:
Private Function EntryLabel(ByVal action As String, ByVal detail As String, _
Optional ByVal source As String = vbNullString) As String
The label opens with the timestamp and the platform; the procedure, the action code and the detail follow behind the separator, so the two halves land in their own columns of the log sheet. A separator inside the free text would push it past the last written column, so it is softened to a single dash. The platform is on every line on purpose: a log rotation clears the sheet, so a platform written once at the top of a session would be lost with it.
Parameters:
action: String. The action code of the event.detail: String. Short free text beside the timestamp.source: String. The procedure that raised the event. May be empty.
Returns: String. The composed label.
Soften #
soften
Take the column separator out of a piece of free text
Signature:
Private Function Soften(ByVal text As String) As String
CheckingOutput splits the label on the separator and lays the pieces across three columns, so a separator inside free text would push the rest of the line past the last written column and out of the sheet.
Parameters:
text: String. The free text.
Returns: String. The text with every separator turned into a single dash.
PlatformTag #
platform-tag
The operating system, the bitness and the Excel version, on one tag
Signature:
Private Function PlatformTag() As String
A log read months later has to say where it was written, since the same code behaves differently on the two platforms. The name and the bitness come from the compile constants; the Excel version comes from the application and is read once, because it is the same for every line of a session.
Returns: String. Something of the shape "win-64 excel-16.0".
RotateWhenPastCap #
rotate-when-past-cap
Clear the sheet and restart the log once the cap is passed
Signature:
Private Sub RotateWhenPastCap()
Reads the last written row of the output column. Past the cap, the sheet is cleared and the row marker removed, so CheckingOutput re-initialises on the next render, and the fresh log opens with one info line.
Writer #
writer
Lazily create and return the CheckingOutput writer
Signature:
Private Function Writer() As CheckingOutput
The writer is asked for compact appending, which is the mode a log wants: a section title is written the first time the sheet carries it and never again, and no blank rows stand between the entries of one block.
Returns: CheckingOutput. Writer bound to the log worksheet.
HiddenStore #
hidden-store
Lazily create and return the HiddenNames store of the log sheet
Signature:
Private Function HiddenStore() As HiddenNames
Returns: HiddenNames. Hidden name store bound to the log worksheet.
ErrorHandling
ThrowError #
throw-error
Raise a ProjectError-coded runtime error
Signature:
Private Sub ThrowError(ByVal errNumb As Long, ByVal errorMessage As String)
Centralised error-raising pattern and the set-once seal.
Parameters:
errNumb: Long. ProjectError enumeration value.errorMessage: String. Human-readable description.
Throws:
- ProjectError.
Always raises the specified error.
Seal #
seal
Seal the instance so setup setters can no longer be written
Signature:
Public Sub Seal()
GuardNotSealed #
guard-not-sealed
Guard a setup setter against writes after sealing
Signature:
Private Sub GuardNotSealed(ByVal propName As String)
Parameters:
propName: String. Name of the property being guarded.
Used in (7 file(s))
- DiseaseComparisonReport.cls
- EventMasterSetup.cls
- MasterSetupPreparation.cls
- EventsMasterSetupRibbon.bas
- MasterSetupEventsManager.bas
- MasterSetupExports.bas
- TestMasterSetupLog.bas