Repository navigation
Logging
Cimian's enhanced logging system provides structured, timestamped logging designed for modern monitoring and analysis tools. Inspired by both MunkiReport's data collection patterns and Munki's logging practices, this system is optimized for osquery integration and ReportMate compatibility.
C:\ProgramData\ManagedInstalls\logs\
├── 2025-07-12/ # Day directory (YYYY-MM-DD)
│ ├── 1405/ # Session directory (HHMM)
│ │ ├── session.json # Session metadata
│ │ ├── events.jsonl # Streaming event log (JSON Lines)
│ │ ├── install.log # Human-readable format
│ │ └── run.log # Per-session run log
│ └── 1200/ # Earlier session today
├── 2025-07-11/
│ └── 1600/ # Yesterday's session
C:\ProgramData\ManagedInstalls\reports\ # Pre-computed tables for external tools
├── sessions.json # Session summary table
├── events.json # Event detail table
├── items.json # Per-item status table
├── packages.json # Package statistics table
└── run.log # Truncated each session — latest run trace
-
Format:
logs/YYYY-MM-DD/HHMM/— day-nested directories with per-session minute subdirectories (no seconds) -
Collision handling: Same-minute collisions append
_2.._9suffix to the time directory -
Session ID:
YYYY-MM-DD-HHMM(matches the directory path) -
Retention: Background cleanup runs at session start (see
PerformRetentionCleanupinSessionLogger.cs)
- Compatible Tables: Pre-configured table schemas for external monitoring tools
- JSON Format: All logs stored in queryable JSON format
- Event Streaming: Real-time event logging for monitoring
- Aggregated Views: Pre-computed data tables for efficient querying
- Data Export: Native ReportMate format export
- Session Tracking: Comprehensive session management
- Summary Reports: Aggregated installation statistics
- Core Architecture: Timestamped directory structure, structured logging system
- External Tool Integration: Table schemas, data export, query examples
- ReportMate Compatibility: Export layer, data transformation, session summaries
- Background Cleanup: Automatic maintenance routines
[
{
"session_id": "2025-01-12-1430",
"start_time": "2025-01-12T14:30:52Z",
"end_time": "2025-01-12T14:31:16Z",
"run_type": "manual",
"status": "completed",
"duration_seconds": 24,
"total_actions": 3,
"installs": 1,
"updates": 0,
"removals": 0,
"successes": 1,
"failures": 1,
"hostname": "WORKSTATION-01",
"user": "SYSTEM",
"process_id": 4512,
"log_version": "2.0"
}
]Purpose: High-level session summaries for dashboard overviews and trending analysis.
[
{
"event_id": "2025-01-12-1430-1736689853000000000",
"session_id": "2025-01-12-1430",
"timestamp": "2025-01-12T14:30:53Z",
"level": "INFO",
"event_type": "install",
"package": "Firefox",
"version": "119.0.1",
"action": "install_package",
"status": "started",
"message": "Package installation started",
"duration_ms": 0,
"progress": 0,
"source_file": "InstallerService.cs",
"source_function": "InstallerService.InstallPackageAsync",
"source_line": 156
}
]Purpose: Detailed event tracking for troubleshooting and performance analysis.
[
{
"package_name": "Firefox",
"latest_version": "119.0.1",
"last_install_time": "2025-01-12T14:30:58Z",
"last_update_time": "2025-01-08T09:15:22Z",
"install_count": 3,
"update_count": 8,
"removal_count": 0,
"last_install_status": "success",
"total_sessions": 15
}
]Purpose: Aggregated package statistics for inventory management and success rate tracking.
-
auto: Scheduled automatic runs -
manual: User-initiated runs -
bootstrap: Zero-touch deployment mode -
ondemand: Triggered by external events
-
Start: Create day/time-nested directory (
logs/YYYY-MM-DD/HHMM/) andsession.json -
Logging: Stream events to
events.jsonl, human log toinstall.log, run trace torun.log -
Progress: Periodically rewrite
session.jsonandreports/run.log -
Completion: Finalize
session.json, regeneratereports/sessions.json,events.json, anditems.jsonaggregates
using Cimian.Core.Services;
// Initialize logging system (normally wired via DI during host build)
var sessionLogger = new SessionLogger(config);
// Basic logging with key-value pairs
sessionLogger.Info("Package installation started",
("package", "Firefox"), ("version", "119.0.1"));
sessionLogger.Error("Installation failed",
("error_code", 1603), ("package", "Chrome"));// For external tool compatibility with explicit properties
var properties = new Dictionary<string, object?>
{
["package_name"] = "Firefox",
["installer_type"] = "MSI",
};
sessionLogger.LogStructured(LogLevel.Information, "Package installation completed", properties);// Get current session information
var logDir = sessionLogger.CurrentLogDirectory;
var sessionId = sessionLogger.SessionId;
// Update run type during execution
sessionLogger.SetRunType("manual"); // manual, scheduled, autoCREATE TABLE cimian_sessions (
session_id TEXT PRIMARY KEY,
start_time BIGINT,
end_time BIGINT,
run_type TEXT,
status TEXT,
duration_seconds INTEGER,
total_actions INTEGER,
installs INTEGER,
updates INTEGER,
removals INTEGER,
successes INTEGER,
failures INTEGER,
hostname TEXT,
user TEXT,
process_id INTEGER,
log_version TEXT
);
CREATE TABLE cimian_events (
event_id TEXT PRIMARY KEY,
session_id TEXT,
timestamp BIGINT,
level TEXT,
event_type TEXT,
package TEXT,
version TEXT,
action TEXT,
status TEXT,
message TEXT,
duration_ms INTEGER,
progress INTEGER,
source_file TEXT,
source_function TEXT,
source_line INTEGER
);
CREATE TABLE cimian_packages (
package_name TEXT PRIMARY KEY,
latest_version TEXT,
last_install_time BIGINT,
last_update_time BIGINT,
install_count INTEGER,
update_count INTEGER,
removal_count INTEGER,
last_install_status TEXT,
total_sessions INTEGER
);Recent Installation Activity:
-- Query sessions
SELECT * FROM file
WHERE path = 'C:\ProgramData\ManagedInstalls\reports\sessions.json';
-- Query events
SELECT * FROM file
WHERE path = 'C:\ProgramData\ManagedInstalls\reports\events.json';
-- Query packages
SELECT * FROM file
WHERE path = 'C:\ProgramData\ManagedInstalls\reports\packages.json';Installation Success Rate:
SELECT
run_type,
COUNT(*) as total_sessions,
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as successful,
ROUND(
(SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) * 100.0) / COUNT(*), 2
) as success_rate
FROM cimian_sessions
WHERE start_time > strftime('%s', 'now', '-30 days')
GROUP BY run_type;Package Status Overview:
SELECT
package_name,
latest_version,
datetime(last_install_time, 'unixepoch') as last_installed,
install_count,
last_install_status
FROM cimian_packages
ORDER BY last_install_time DESC;The data is automatically exported in a format compatible with ReportMate's data collection system. The JSON structure maps directly to database tables for efficient storage and querying.
Export Format:
{
"hostname": "DESKTOP-ABC123",
"timestamp": "2025-07-12T14:05:30Z",
"session_id": "2025-07-12-1405",
"event_type": "install",
"package_name": "Firefox",
"version": "119.0.1",
"status": "success",
"duration_ms": 15000
}Any tool that can consume JSON data can easily integrate with this structure. The clean separation of concerns makes it easy to:
- Monitor session health (
sessions.json) - Analyze specific failures (
events.json) - Track package deployment status (
packages.json)
- Sessions: Last 30 days
- Events: Last 7 days (for performance)
- Packages: Continuously updated aggregated view
- Individual Logs: Per retention policy (10 days daily + 24 hours hourly)
- Memory: ~10MB for structured logger
- CPU: <1% overhead during logging
- Disk: 2-5MB per session
- I/O: Batched writes every 5 seconds
The Windows Service monitor is designed to be lightweight:
- CPU Usage: < 0.1% average
- Memory Usage: < 5MB
- Disk I/O: Minimal (file existence check every 10 seconds)
- Network Usage: None (local monitoring only)
C:\ProgramData\ManagedInstalls\logs\
└── install.log # Everything dumped here - grows indefinitely
C:\ProgramData\ManagedInstalls\logs\
├── 2025-07-12/
│ ├── 1405/ # Session directory (HHMM)
│ │ ├── session.json # Session metadata
│ │ ├── events.jsonl # Event stream
│ │ ├── install.log # Human-readable log
│ │ └── run.log # Per-session run trace
│ └── 1200/ # Earlier session
C:\ProgramData\ManagedInstalls\reports\ # Pre-computed aggregated views
├── sessions.json
├── events.json
├── items.json
└── packages.json
- Performance: Pre-computed aggregated views eliminate need to parse hundreds of individual session files
- Separation: Reports are separate from operational logs, reducing I/O contention
- Simplicity: Clean filenames without tool-specific prefixes
- Compatibility: Standard JSON format works with any monitoring tool
- Readability: Pretty-formatted JSON for human inspection and debugging
-
Legacy Path Support: Old
install.logpath still works - API Compatibility: All existing logging calls unchanged
- Gradual Migration: Systems can transition gradually
- Fallback Mechanisms: Graceful degradation if new system unavailable
-
Backup Legacy: Existing
install.logbacked up automatically - Parse History: Extract historical events where possible
- Convert Format: Transform to new structured format
- Maintain Compatibility: Run both systems during transition
shared/core/Services/
├── SessionLogger.cs Per-session structured JSONL event streams
├── ConsoleLogger.cs Console output with level filtering
└── DataExporter.cs osquery / ReportMate export layer
- Integration: Update existing Cimian components to use new logging
- Testing: Comprehensive testing with signed binaries
- Deployment: Roll out to production environments
- Monitoring Setup: Connect to monitoring dashboards
- Documentation: Update API documentation and examples
-- Cimian Logging Health Check
SELECT 'Cimian Logging Health' as check_name,
CASE WHEN COUNT(*) > 0 THEN 'OK' ELSE 'CRITICAL' END as status
FROM cimian_sessions
WHERE start_time > strftime('%s', 'now', '-1 hour');- Missing Log Directories: Automatically created on first use
- Permission Issues: Service runs as SYSTEM with appropriate access
- Disk Space: Automatic cleanup prevents excessive storage usage
- Performance: Batched logging minimizes I/O impact
This unified logging system provides comprehensive monitoring capabilities while maintaining backward compatibility and supporting modern external tool integration.
Cimian — managed software deployment for Windows, modelled on Munki. Apache License 2.0. Source and issues at windowsadmins/cimian.
Start here
Repository
Authoring packages
- Installation Checks
- Uninstall Methods
- Uninstallable Key
- Conditional Items
- Importing EXE Bundle Installers
- PowerShell Execution Policy
- Chocolatey Shim Prevention
- Managed Profiles and Apps
Client runtime
Diagnostics
- Troubleshooting
- Logging
- Error Reporting
- Item Source Traceability
- CimiTrigger Troubleshooting
- Privilege Elevation
Integrations
Contributing