Documentation
¶
Overview ¶
internal/logging/catalog.go
This file is the single source of truth for every event gitback can log. Logger.Emit only accepts an EventDef — there is no way to log a bare string — so adding a new log line always means adding an entry here first.
Rules for adding a new event:
- Pick the right Component* constant (types.go). Add a new one only if this event genuinely belongs to a subsystem that doesn't have one yet.
- Give it a Code unique within that Component, snake_case, verb-led ("clone_failed", not "failed_clone").
- Set Level to the severity this event ALWAYS has. If the same condition is sometimes worse than other times, that's two events, not one event logged at two levels.
- Write Message as a fixed, complete description — no variables. Good: "Failed to clone repository mirror". Bad: "clone failed".
- Write Remediation for anything Warn or above: a concrete next action. Leave it empty only for Info, or when the action really is "nothing — this will be retried automatically" (say that).
- Check whether an existing EventDef already fits before adding a new one — don't create "clone_error" next to "clone_failed".
Index ¶
- Constants
- Variables
- func CurrentLogFilePath(logDir string) string
- type Cause
- type ConfigEvents
- type DoctorEvents
- type Entry
- type EventCatalog
- type EventDef
- type GitHubEvents
- type HealthEvents
- type InventoryEvents
- type Level
- type LockEvents
- type LogRetentionEvents
- type Logger
- type MirrorEvents
- type Option
- type SnapshotEvents
- type SyncEvents
Constants ¶
const ( ComponentConfig = "config" ComponentGitHub = "github" ComponentInventory = "inventory" ComponentMirror = "mirror" ComponentSync = "sync" ComponentSnapshot = "snapshot" ComponentLock = "lock" ComponentHealth = "health" ComponentFilesystem = "filesystem" ComponentDoctor = "doctor" ComponentLogRetention = "log_retention" )
Component names the internal subsystem an event belongs to. Constants, not free strings — a typo in catalog.go becomes a compile error instead of a silently-wrong value shipped to every consumer.
Variables ¶
var Events = EventCatalog{ Config: ConfigEvents{ TokenSourceResolved: EventDef{ Component: ComponentConfig, Code: "token_source_resolved", Level: Info, Message: "GitHub token resolved for use", }, }, GitHub: GitHubEvents{ DiscoveryStarted: EventDef{ Component: ComponentGitHub, Code: "discovery_started", Level: Info, Message: "GitHub discovery started", }, DiscoveryCompleted: EventDef{ Component: ComponentGitHub, Code: "discovery_completed", Level: Info, Message: "GitHub discovery completed for a resource type", }, DiscoveryFailed: EventDef{ Component: ComponentGitHub, Code: "discovery_failed", Level: Error, Message: "GitHub discovery failed", Remediation: "Run `gitback doctor` to check network connectivity and token validity, then retry.", }, DiscoverySummary: EventDef{ Component: ComponentGitHub, Code: "discovery_summary", Level: Info, Message: "GitHub discovery run summary", }, PageFetched: EventDef{ Component: ComponentGitHub, Code: "page_fetched", Level: Info, Message: "Fetched a page of results from the GitHub API", }, InventoryLoaded: EventDef{ Component: ComponentGitHub, Code: "inventory_loaded", Level: Info, Message: "Inventory file written", }, RateLimit: EventDef{ Component: ComponentGitHub, Code: "rate_limit", Level: Info, Message: "GitHub API rate limit status", }, }, Inventory: InventoryEvents{ Missing: EventDef{ Component: ComponentInventory, Code: "missing", Level: Warn, Message: "Inventory file not found", Remediation: "Run `gitback discover` to generate it.", }, Empty: EventDef{ Component: ComponentInventory, Code: "empty", Level: Warn, Message: "Inventory file is empty", Remediation: "Run `gitback discover` to populate it.", }, ReadFailed: EventDef{ Component: ComponentInventory, Code: "read_failed", Level: Error, Message: "Inventory file could not be read", Remediation: "Check file permissions; if the file is corrupted, run `gitback discover` to regenerate it.", }, }, Mirror: MirrorEvents{ CloneStarted: EventDef{ Component: ComponentMirror, Code: "clone_started", Level: Info, Message: "Mirror clone started", }, CloneCompleted: EventDef{ Component: ComponentMirror, Code: "clone_completed", Level: Info, Message: "Mirror clone completed", }, CloneFailed: EventDef{ Component: ComponentMirror, Code: "clone_failed", Level: Error, Message: "Mirror clone failed", Remediation: "Check network connectivity and GitHub token permissions; gitback retries automatically on the next sync.", }, UpdateStarted: EventDef{ Component: ComponentMirror, Code: "update_started", Level: Info, Message: "Mirror update started", }, UpdateCompleted: EventDef{ Component: ComponentMirror, Code: "update_completed", Level: Info, Message: "Mirror update completed", }, UpdateFailed: EventDef{ Component: ComponentMirror, Code: "update_failed", Level: Error, Message: "Mirror update failed", Remediation: "Check network connectivity and GitHub token permissions; gitback retries automatically on the next sync.", }, Retry: EventDef{ Component: ComponentMirror, Code: "retry", Level: Warn, Message: "Retrying a failed git operation", Remediation: "No action needed yet; investigate if this repository keeps failing across multiple sync runs.", }, FsckStarted: EventDef{ Component: ComponentMirror, Code: "fsck_started", Level: Info, Message: "Mirror integrity check started", }, FsckCompleted: EventDef{ Component: ComponentMirror, Code: "fsck_completed", Level: Info, Message: "Mirror integrity check passed", }, FsckFailed: EventDef{ Component: ComponentMirror, Code: "fsck_failed", Level: Error, Message: "Mirror integrity check failed", Remediation: "The mirror will be quarantined and gitback will attempt automatic recovery via a fresh clone.", }, QuarantineStarted: EventDef{ Component: ComponentMirror, Code: "quarantine_started", Level: Info, Message: "Corrupt mirror quarantine started", }, QuarantineCompleted: EventDef{ Component: ComponentMirror, Code: "quarantine_completed", Level: Info, Message: "Corrupt mirror quarantined", }, QuarantineFailed: EventDef{ Component: ComponentMirror, Code: "quarantine_failed", Level: Error, Message: "Failed to quarantine a corrupt mirror", Remediation: "Check filesystem permissions on the quarantine directory; manual intervention may be required.", }, QuarantineCleanupCompleted: EventDef{ Component: ComponentMirror, Code: "quarantine_cleanup_completed", Level: Info, Message: "Quarantined copies removed after successful recovery", }, QuarantineCleanupFailed: EventDef{ Component: ComponentMirror, Code: "quarantine_cleanup_failed", Level: Warn, Message: "Failed to remove a quarantined mirror after recovery", Remediation: "Manually inspect and remove the stale entry under the quarantine directory.", }, CorruptionDetected: EventDef{ Component: ComponentMirror, Code: "corruption_detected", Level: Critical, Message: "Mirror corruption detected", Remediation: "gitback will quarantine the mirror and attempt automatic recovery via a fresh clone.", }, RecoverySucceeded: EventDef{ Component: ComponentMirror, Code: "recovery_succeeded", Level: Info, Message: "Corrupt mirror recovered successfully", }, RecoveryFailed: EventDef{ Component: ComponentMirror, Code: "recovery_failed", Level: Critical, Message: "Automatic recovery of a corrupt mirror failed", Remediation: "Manual intervention required: inspect the quarantined mirror and consider a manual re-clone.", }, StateSaveFailed: EventDef{ Component: ComponentMirror, Code: "state_save_failed", Level: Error, Message: "Failed to save mirror sync state", Remediation: "Check disk space and permissions on the state directory; this run's results may be missing from `gitback health`.", }, CloneInterrupted: EventDef{ Component: ComponentMirror, Code: "clone_interrupted", Level: Warn, Message: "Mirror clone was interrupted before completion", Remediation: "Re-run `gitback sync` to retry this repository.", }, UpdateInterrupted: EventDef{ Component: ComponentMirror, Code: "update_interrupted", Level: Warn, Message: "Mirror update was interrupted before completion", Remediation: "Re-run `gitback sync` to retry this repository.", }, FsckInterrupted: EventDef{ Component: ComponentMirror, Code: "fsck_interrupted", Level: Warn, Message: "Mirror integrity check was interrupted before completion", Remediation: "Re-run `gitback sync`; this mirror was not modified.", }, RecoveryInterrupted: EventDef{ Component: ComponentMirror, Code: "recovery_interrupted", Level: Warn, Message: "Automatic recovery was interrupted (e.g. ctrl+c) before completion", Remediation: "The mirror remains safely quarantined; re-run `gitback sync` to retry recovery.", }, RecoveryDeferred: EventDef{ Component: ComponentMirror, Code: "recovery_deferred", Level: Warn, Message: "Automatic recovery deferred due to interruption (e.g. ctrl+c)", Remediation: "Re-run `gitback sync`; the mirror will be re-cloned fresh.", }, }, Sync: SyncEvents{ Started: EventDef{ Component: ComponentSync, Code: "started", Level: Info, Message: "Sync started", }, Completed: EventDef{ Component: ComponentSync, Code: "completed", Level: Info, Message: "Sync completed", }, Failed: EventDef{ Component: ComponentSync, Code: "failed", Level: Error, Message: "Sync failed", Remediation: "Check the error details and run `gitback doctor` to diagnose the environment.", }, Summary: EventDef{ Component: ComponentSync, Code: "summary", Level: Info, Message: "Sync run summary", }, Interrupted: EventDef{ Component: ComponentSync, Code: "interrupted", Level: Warn, Message: "Sync was interrupted before completion", Remediation: "Rerun `gitback sync` to finish backing up any remaining repositories.", }, }, Snapshot: SnapshotEvents{ Started: EventDef{ Component: ComponentSnapshot, Code: "started", Level: Info, Message: "Snapshot creation started", }, Completed: EventDef{ Component: ComponentSnapshot, Code: "completed", Level: Info, Message: "Snapshot creation completed", }, Failed: EventDef{ Component: ComponentSnapshot, Code: "failed", Level: Error, Message: "Snapshot creation failed", Remediation: "Ensure `tar` and `zstd` are installed and the snapshot output directory is writable, then retry.", }, VerificationStarted: EventDef{ Component: ComponentSnapshot, Code: "verification_started", Level: Info, Message: "Pre-snapshot mirror verification started", }, VerificationPassed: EventDef{ Component: ComponentSnapshot, Code: "verification_passed", Level: Info, Message: "Pre-snapshot mirror verification passed", }, VerificationFailed: EventDef{ Component: ComponentSnapshot, Code: "verification_failed", Level: Error, Message: "Pre-snapshot mirror verification failed", Remediation: "Run `gitback sync` to fix failing mirrors, or re-run with `--force` to snapshot anyway.", }, ArchiveStarted: EventDef{ Component: ComponentSnapshot, Code: "archive_started", Level: Info, Message: "Snapshot archive creation started", }, ArchiveCompleted: EventDef{ Component: ComponentSnapshot, Code: "archive_completed", Level: Info, Message: "Snapshot archive creation completed", }, CompressionStarted: EventDef{ Component: ComponentSnapshot, Code: "compression_started", Level: Info, Message: "Snapshot compression started", }, CompressionCompleted: EventDef{ Component: ComponentSnapshot, Code: "compression_completed", Level: Info, Message: "Snapshot compression completed", }, ChecksumStarted: EventDef{ Component: ComponentSnapshot, Code: "checksum_started", Level: Info, Message: "Snapshot checksum generation started", }, ChecksumCompleted: EventDef{ Component: ComponentSnapshot, Code: "checksum_completed", Level: Info, Message: "Snapshot checksum generation completed", }, Summary: EventDef{ Component: ComponentSnapshot, Code: "summary", Level: Info, Message: "Snapshot run summary", }, RetentionDisabled: EventDef{ Component: ComponentSnapshot, Code: "retention_disabled", Level: Info, Message: "Snapshot retention is disabled", }, RetentionStarted: EventDef{ Component: ComponentSnapshot, Code: "retention_started", Level: Info, Message: "Snapshot retention cleanup started", }, RetentionCompleted: EventDef{ Component: ComponentSnapshot, Code: "retention_completed", Level: Info, Message: "Snapshot retention cleanup completed", }, RetentionFailed: EventDef{ Component: ComponentSnapshot, Code: "retention_failed", Level: Error, Message: "Failed to delete an old snapshot during retention cleanup", Remediation: "Check filesystem permissions on the snapshot output directory.", }, CollisionDetected: EventDef{ Component: ComponentSnapshot, Code: "collision_detected", Level: Error, Message: "Snapshot output path already exists", Remediation: "Remove or move aside the conflicting file, or retry after the current minute has passed.", }, }, Lock: LockEvents{ Acquired: EventDef{ Component: ComponentLock, Code: "acquired", Level: Info, Message: "Process lock acquired", }, Released: EventDef{ Component: ComponentLock, Code: "released", Level: Info, Message: "Process lock released", }, Busy: EventDef{ Component: ComponentLock, Code: "busy", Level: Warn, Message: "Could not acquire the gitback process lock", Remediation: "Another gitback process is already running; wait for it to finish, or check for a stuck process holding the lock file.", }, }, Health: HealthEvents{ HealthReport: EventDef{ Component: ComponentHealth, Code: "report_generated", Level: Info, Message: "Health report generated", }, }, Doctor: DoctorEvents{ ReportGenerated: EventDef{ Component: ComponentDoctor, Code: "report_generated", Level: Info, Message: "Doctor diagnostic report generated", }, }, LogRetention: LogRetentionEvents{ Pruned: EventDef{ Component: ComponentLogRetention, Code: "pruned", Level: Info, Message: "Old log files pruned", }, PruneFailed: EventDef{ Component: ComponentLogRetention, Code: "prune_failed", Level: Warn, Message: "Failed to prune one or more old log files", Remediation: "Check filesystem permissions on the log directory.", }, UnrecognizedFile: EventDef{ Component: ComponentLogRetention, Code: "unrecognized_file", Level: Warn, Message: "Found a file matching gitback's log naming pattern with an unparseable date", Remediation: "Manually inspect the file; remove it if it is not a genuine gitback log file.", }, }, }
Functions ¶
func CurrentLogFilePath ¶ added in v0.5.5
CurrentLogFilePath returns the path New would open right now, given logDir. Used by doctor to check writability without opening a second file handle onto today's log.
Types ¶
type Cause ¶ added in v0.5.5
type Cause string
Cause is a small, fixed taxonomy of failure categories. Unlike Error (the raw, free-text message from whatever failed), Cause is machine-parseable and stable across versions and locales — this is what a SIEM rule or an AI triage pipeline should key off, not string-matching Error text.
Only set Cause when a call site genuinely knows the category for certain. Leaving it empty is correct when the failure hasn't been classified — never guess.
const ( CauseAuthFailure Cause = "auth_failure" CauseNetworkError Cause = "network_error" CausePermissionDenied Cause = "permission_denied" CauseDiskFull Cause = "disk_full" CauseCorruption Cause = "corruption" CauseNotFound Cause = "not_found" CauseAlreadyExists Cause = "already_exists" CauseTimeout Cause = "timeout" CauseCancelled Cause = "cancelled" CauseConfigInvalid Cause = "config_invalid" CauseLockHeld Cause = "lock_held" CauseChecksumMismatch Cause = "checksum_mismatch" )
type ConfigEvents ¶ added in v0.5.6
type ConfigEvents struct {
TokenSourceResolved EventDef
}
ConfigEvents covers credential/config resolution, not sync or snapshot behavior.
type DoctorEvents ¶ added in v0.4.7
type DoctorEvents struct {
ReportGenerated EventDef
}
type Entry ¶
type Entry struct {
SchemaVersion int `json:"schema_version"`
Timestamp string `json:"ts"`
Level Level `json:"level"`
RunID string `json:"run_id"`
Host string `json:"host"`
User string `json:"user"`
Component string `json:"component"`
Event string `json:"event"`
Message string `json:"message"`
// Asset names the specific repository or gist this entry concerns.
// Empty for entries that aren't about one specific mirror (e.g. a
// run-level summary).
Asset string `json:"repo,omitempty"`
DurationMS int64 `json:"duration_ms,omitempty"`
Cause Cause `json:"cause,omitempty"`
// Error is the raw, free-text message from whatever underlying
// operation failed — supplementary detail for deeper analysis.
// Cause is what SIEM rules should match against, not this.
Error string `json:"error,omitempty"`
Remediation string `json:"remediation,omitempty"`
// Details carries structured, event-specific data that doesn't fit
// the fields above — counts, name lists, rate-limit numbers. Not a
// place for narrative text: a sentence that belongs here probably
// belongs in this event's Message or Remediation instead.
Details any `json:"details,omitempty"`
}
Entry is one structured log line. Everything through Message is always present; everything after is populated only when relevant. Field order here is also the emitted JSON field order — kept stable and deliberate so every gitback log line reads the same way, which matters for both human scanning and SIEM/AI field-position assumptions.
type EventCatalog ¶
type EventCatalog struct {
Config ConfigEvents
GitHub GitHubEvents
Inventory InventoryEvents
Mirror MirrorEvents
Sync SyncEvents
Snapshot SnapshotEvents
Lock LockEvents
Health HealthEvents
Doctor DoctorEvents
LogRetention LogRetentionEvents
}
type EventDef ¶ added in v0.5.5
type EventDef struct {
// Component groups this event for filtering (e.g. a SIEM query
// for "mirror.*"). Always one of the Component* constants above.
Component string
// Code identifies this event within Component, e.g. "clone_failed".
// Combined as "<component>.<code>" for the entry's Event field.
Code string
// Level is this event's severity, fixed here rather than chosen
// per call site — so the same conceptual event is never logged at
// inconsistent severities in different places.
Level Level
// Message is a fixed, human-readable summary of what happened —
// the "what". Never overridden per call site; variable context
// (which repo, which path) belongs in Repo/Details, not Message.
Message string
// Remediation is the default "how to fix it" guidance, shown
// directly in the log entry so a reader never has to cross-
// reference a separate runbook. Required for Warn/Error/Critical
// events with a knowable fix; empty is correct for Info events.
// A call site may override this with WithRemediation when it has
// more specific guidance (e.g. a concrete file path).
Remediation string
}
EventDef is the single declaration point for one kind of log entry. See catalog.go's package doc for the rules governing how these are added.
type GitHubEvents ¶
type HealthEvents ¶
type HealthEvents struct {
HealthReport EventDef
}
type InventoryEvents ¶ added in v0.4.4
type LockEvents ¶
type LogRetentionEvents ¶ added in v0.5.5
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
func New ¶
New opens (creating if needed) today's log file under logDir.
Local time decides the filename here, resolved once, at open time — not recomputed anywhere else in the Logger. Each gitback command is one short-lived process with exactly one Logger for its whole run, so a run spanning local midnight keeps writing to the file it opened at start; nothing re-checks the date mid-run.
retentionDays prunes old log files in logDir; <= 0 disables pruning.
type MirrorEvents ¶
type MirrorEvents struct {
CloneStarted EventDef
CloneCompleted EventDef
CloneFailed EventDef
UpdateStarted EventDef
UpdateCompleted EventDef
UpdateFailed EventDef
Retry EventDef
FsckStarted EventDef
FsckCompleted EventDef
FsckFailed EventDef
QuarantineStarted EventDef
QuarantineCompleted EventDef
QuarantineFailed EventDef
QuarantineCleanupCompleted EventDef
QuarantineCleanupFailed EventDef
CorruptionDetected EventDef
RecoverySucceeded EventDef
RecoveryFailed EventDef
StateSaveFailed EventDef
CloneInterrupted EventDef
UpdateInterrupted EventDef
FsckInterrupted EventDef
RecoveryInterrupted EventDef
RecoveryDeferred EventDef
}
type Option ¶ added in v0.5.5
type Option func(*Entry)
Option customizes one Entry beyond what its EventDef fixes.
func WithAsset ¶ added in v0.5.5
WithAsset sets the specific repository or gist this entry concerns.
func WithCause ¶ added in v0.5.5
WithCause classifies the failure into one of the fixed Cause categories. Only use when the call site genuinely knows the category for certain — never guess.
func WithDetails ¶ added in v0.5.5
WithDetails attaches structured, event-specific data (counts, name lists) that doesn't fit Entry's named fields. Not for narrative text — see Entry.Details's doc comment.
func WithDuration ¶ added in v0.5.5
WithDuration records how long the described operation took.
func WithError ¶ added in v0.5.5
WithError attaches the raw, free-text message of the underlying error. Safe to call with a nil error — it's a no-op in that case, so call sites don't need their own nil check first.
func WithRemediation ¶ added in v0.5.5
WithRemediation overrides this event's default Remediation with more specific guidance — typically because the call site has a concrete path or value the generic default can't include.
type SnapshotEvents ¶
type SnapshotEvents struct {
Started EventDef
Completed EventDef
Failed EventDef
VerificationStarted EventDef
VerificationPassed EventDef
VerificationFailed EventDef
ArchiveStarted EventDef
ArchiveCompleted EventDef
CompressionStarted EventDef
CompressionCompleted EventDef
ChecksumStarted EventDef
ChecksumCompleted EventDef
Summary EventDef
RetentionDisabled EventDef
RetentionStarted EventDef
RetentionCompleted EventDef
RetentionFailed EventDef
CollisionDetected EventDef
Interrupted EventDef
}