---
url: /logly.zig/api/scheduler.md
description: >-
  API reference for Logly.zig Scheduler module. Automatic log maintenance with
  scheduled cleanup, compression, rotation, cron expressions, and custom
  periodic tasks.
---

# Scheduler API

The scheduler module provides automatic log maintenance with scheduled cleanup, compression, rotation, and custom tasks. It runs in the background using either a dedicated worker thread or by submitting tasks to a shared `ThreadPool`.

## Quick Reference: Method Aliases

| Full Method | Alias(es) | Description |
|-------------|-----------|-------------|
| `init()` | `create()` | Initialize scheduler |
| `initFromConfig()` | `fromConfig()` | Initialize from config |
| `deinit()` | `destroy()` | Deinitialize scheduler |
| `setHealthCallback()` | `onHealth()` | Set health callback |
| `setMetricsCallback()` | `onMetrics()` | Set metrics callback |
| `getHealthStatus()` | `healthStatus()` | Get health status |
| `getMetrics()` | `snapshot()` | Get metrics snapshot |
| `addTask()` | `add()` | Add a task |
| `setTaskPriority()` | `setPriority()` | Set task priority |
| `setTaskRetryPolicy()` | `retry()` | Set task retry policy |
| `setTaskDependency()` | `dependsOn()` | Set task dependency |
| `addCleanupTask()` | `cleanup()` | Add cleanup task |
| `addCompressionTask()` | `compress()` | Add compression task |
| `addCustomTask()` | `custom()` | Add custom task |
| `setTaskEnabled()` | `enable()` | Enable/disable task |
| `removeTask()` | `remove()` | Remove task |
| `taskIndexByName()` | `indexOfTask()` | Find task index by name |
| `getTaskSnapshot()` | `snapshotTask()` | Get immutable task snapshot by index |
| `getTaskSnapshotByName()` | `snapshotTaskByName()` | Get immutable task snapshot by name |
| `hasTaskNamed()` | `hasTask()` | Check task existence by name |
| `setTaskEnabledByName()` | `enableByName()` | Enable/disable task by name |
| `removeTaskByName()` | `removeNamed()` | Remove task by name |
| `enabledTaskCount()` | `enabledCount()` | Count enabled tasks |
| `runningTaskCount()` | `runningCount()` | Count running tasks |
| `readyTaskCount()` | `readyCount()` | Count tasks ready to run |
| `nextRunInMs()` | `nextRunMs()` | Get ms until task next run |
| `nextRunInMsByName()` | `nextRunForTask()` | Get ms until task next run by name |
| `setTaskSchedule()` | `updateSchedule()` | Update task schedule |
| `rescheduleNow()` | `runSoon()` | Force task runnable immediately |
| `setTaskStartedCallback()` | `onStarted()` | Set task started callback |
| `setTaskCompletedCallback()` | `onCompleted()` | Set task completed callback |
| `setTaskErrorCallback()` | `onError()` | Set task error callback |
| `setScheduleTickCallback()` | `onTick()` | Set tick callback |
| `setHealthCheckCallback()` | `onHealthCheck()` | Set health check callback |
| `runNow()` | `run()` | Run task immediately |
| `runNowByName()` | `runNamed()` | Run task immediately by name |
| `runPending()` | `pending()` | Run pending tasks |
| `start()` | `begin()` | Start scheduler |
| `stop()` | `end()`, `halt()` | Stop scheduler |
| `getStats()` | `statistics()` | Get scheduler statistics |
| `resetStats()` | `clearStats()` | Reset statistics |
| `setTelemetry()` | `trace()` | Set telemetry |
| `clearTelemetry()` | `noTelemetry()` | Clear telemetry |
| `getTasks()` | `tasks_()` | Get tasks |
| `taskCount()` | `count()` | Get task count |
| `isRunning()` | `running_()` | Check if running |
| `hasTasks()` | `has_()` | Check if has tasks |

## Overview

```zig
const logly = @import("logly");
const Scheduler = logly.Scheduler;
const SchedulerPresets = logly.SchedulerPresets;
```

## Centralized Configuration

Scheduler can be enabled through the central `Config` struct:

```zig
var config = logly.Config.default();
config.scheduler = .{
    .enabled = true,
    .cleanupMaxAgeDays = 14,
    .maxFiles = 100,
    .compressBeforeCleanup = true,
    .filePattern = "*.log",
};
const logger = try logly.Logger.initWithConfig(allocator, config);
```

Or use the fluent API:

```zig
const config = logly.Config.default().withScheduler(.{});
```

## Types

### Scheduler

The main scheduler struct for managing scheduled tasks with optional telemetry integration.

```zig
pub const Scheduler = struct {
    allocator: std.mem.Allocator,
    tasks: std.ArrayList(ScheduledTask),
    stats: SchedulerStats,
    compression: Compression,  // Integrated compression support
    running: std.atomic.Value(bool),
    workerThread: ?std.Thread,
    telemetry: ?*Telemetry,    // Optional telemetry for distributed tracing
};
```

### SchedulerConfig (Centralized)

Configuration available through `Config.SchedulerConfig`:

```zig
pub const SchedulerConfig = struct {
    /// Enable the scheduler.
    enabled: bool = false,
    /// Default cleanup max age in days.
    cleanupMaxAgeDays: u64 = 7,
    /// Default max files to keep.
    maxFiles: ?usize = null,
    /// Enable compression before cleanup.
    compressBeforeCleanup: bool = false,
    /// Default file pattern for cleanup.
    filePattern: []const u8 = "*.log",
    /// Root directory for compressed/archived files.
    archiveRootDir: ?[]const u8 = null,
    /// Create date-based subdirectories (YYYY/MM/DD).
    createDateSubdirs: bool = false,
    /// Compression algorithm for scheduled compression tasks.
    compressionAlgorithm: CompressionConfig.CompressionAlgorithm = .gzip,
    /// Compression level for scheduled tasks.
    compressionLevel: CompressionConfig.CompressionLevel = .default,
    /// Keep original files after scheduled compression.
    keepOriginals: bool = false,
    /// Custom prefix for archived file names.
    archiveFilePrefix: ?[]const u8 = null,
    /// Custom suffix for archived file names.
    archiveFileSuffix: ?[]const u8 = null,
    /// Preserve directory structure in archive root.
    preserveDirStructure: bool = true,
    /// Delete empty directories after cleanup.
    cleanEmptyDirs: bool = false,
    /// Minimum file age in days before compression.
    minAgeDaysForCompression: u64 = 1,
    /// Maximum concurrent compression tasks.
    maxConcurrentCompressions: usize = 2,
};
```

### SchedulerConfig Field Reference

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `enabled` | `bool` | `false` | Enable the scheduler |
| `cleanupMaxAgeDays` | `u64` | `7` | Max age for cleanup tasks |
| `maxFiles` | `?usize` | `null` | Max files to retain |
| `compressBeforeCleanup` | `bool` | `false` | Compress before deleting |
| `filePattern` | `[]const u8` | `"*.log"` | File pattern for tasks |
| `archiveRootDir` | `?[]const u8` | `null` | Centralized archive location |
| `createDateSubdirs` | `bool` | `false` | Create YYYY/MM/DD subdirs |
| `compressionAlgorithm` | `CompressionAlgorithm` | `.gzip` | Algorithm for compression (gzip, zlib, deflate, zstd, lzma, lzma2, xz, zip, tar.gz, lz4) |
| `compressionLevel` | `CompressionLevel` | `.default` | Compression level |
| `keepOriginals` | `bool` | `false` | Keep originals after compression |
| `archiveFilePrefix` | `?[]const u8` | `null` | Prefix for archived files |
| `archiveFileSuffix` | `?[]const u8` | `null` | Suffix for archived files |
| `preserveDirStructure` | `bool` | `true` | Keep directory structure |
| `cleanEmptyDirs` | `bool` | `false` | Remove empty directories |
| `minAgeDaysForCompression` | `u64` | `1` | Min age before compression |
| `maxConcurrentCompressions` | `usize` | `2` | Max parallel compressions |

> Note: v0.1.6 expanded compression and archiving support — including LZMA, LZMA2, XZ, TAR.GZ, ZIP, and LZ4 — and added helper utilities (e.g., `Utils.getCompressionExtension()`) and factory presets to simplify usage. Use the `compressionAlgorithm` and `compressionLevel` fields (or the `Compression` factory methods) to select the appropriate algorithm and extension for your scheduled compression tasks.

### ScheduledTask

A scheduled task configuration.

```zig
pub const ScheduledTask = struct {
    /// Unique task name
    name: []const u8,
    /// Task type
    taskType: TaskType,
    /// Schedule configuration
    schedule: Schedule,
    /// Task-specific configuration
    config: TaskConfig,
    /// Task execution callback (for custom tasks)
    callback: ?*const fn (*ScheduledTask) anyerror!void = null,
    /// Whether task is enabled
    enabled: bool = true,
    /// Whether task is currently running
    running: bool = false,
    /// Task execution priority
    priority: Priority = .normal,
    /// Retry policy for failed tasks
    retryPolicy: RetryPolicy = .{},
    /// Name of another task that must complete successfully before this one runs
    dependsOn: ?[]const u8 = null,
    /// Last execution timestamp
    lastRun: i64 = 0,
    /// Next scheduled execution
    nextRun: i64 = 0,
    /// Number of executions
    runCount: u64 = 0,
    /// Number of failures
    errorCount: u64 = 0,
    /// Retries remaining for current failure
    retriesRemaining: u32 = 0,

    pub const Priority = enum {
        low,
        normal,
        high,
        critical,
    };

    pub const RetryPolicy = struct {
        maxRetries: u32 = 3,
        intervalMs: u32 = 5000,
        backoffMultiplier: f32 = 1.5,
    };
};
```

### TaskType

Types of scheduled tasks.

```zig
pub const TaskType = enum {
    /// Clean up old log files
    cleanup,
    /// Rotate log files
    rotation,
    /// Compress log files
    compression,
    /// Flush all buffers
    flush,
    /// Custom user-defined task
    custom,
    /// Health check
    healthCheck,
    /// Metrics collection
    metricsSnapshot,
};
```

### TaskConfig

Configuration specific to tasks.

```zig
pub const TaskConfig = struct {
    /// Path for file-based tasks
    path: ?[]const u8 = null,
    /// Maximum age in seconds for cleanup
    maxAgeSeconds: u64 = 7 * 24 * 60 * 60,
    /// Maximum files to keep
    maxFiles: ?usize = null,
    /// Maximum total size in bytes
    maxTotalSize: ?u64 = null,
    /// Minimum age in seconds (useful for compression)
    minAgeSeconds: u64 = 0,
    /// File pattern to match (e.g., "*.log")
    filePattern: ?[]const u8 = null,
    /// Compress files before cleanup (compress then delete)
    compressBeforeDelete: bool = false,
    /// Compress files and keep both original and compressed (archive mode)
    compressAndKeep: bool = false,
    /// Only compress files, don't delete any (pure archival)
    compressOnly: bool = false,
    /// Skip files that are already compressed (.gz, .lgz, .zst)
    skipAlreadyCompressed: bool = true,
    /// Recursive directory processing
    recursive: bool = false,
    /// Trigger task only if disk usage exceeds this percentage (0-100)
    triggerDiskUsagePercent: ?u8 = null,
    /// Required free space in bytes before running task
    minFreeSpaceBytes: ?u64 = null,
};
```

#### TaskConfig Compression Modes

| Field | Behavior |
|-------|----------|
| `compressBeforeDelete` | Compress file, then delete original |
| `compressAndKeep` | Compress file, keep both versions |
| `compressOnly` | Compress file, never delete anything |

### Schedule

Schedule configuration.

```zig
pub const Schedule = union(enum) {
    /// Run once after delay (in milliseconds)
    once: u64,
    /// Run at fixed intervals (in milliseconds)
    interval: u64,
    /// Run at specific time of day
    daily: DailySchedule,
    /// Cron-like schedule
    cron: CronSchedule,

    pub const DailySchedule = struct {
        hour: u8 = 0,
        minute: u8 = 0,
    };

    pub const CronSchedule = struct {
        minute: ?u8 = null,
        hour: ?u8 = null,
        dayOfMonth: ?u8 = null,
        month: ?u8 = null,
        dayOfWeek: ?u8 = null,
    };
};
```

### SchedulerStats

Thread-safe statistics for scheduled operations using atomic counters. Works correctly on both 32-bit and 64-bit architectures.

```zig
pub const SchedulerStats = struct {
    /// Total tasks executed successfully (atomic).
    tasksExecuted: std.atomic.Value(Constants.AtomicUnsigned),
    /// Total tasks that failed (atomic).
    tasksFailed: std.atomic.Value(Constants.AtomicUnsigned),
    /// Total files cleaned up (atomic).
    filesCleaned: std.atomic.Value(Constants.AtomicUnsigned),
    /// Total files compressed (atomic).
    filesCompressed: std.atomic.Value(Constants.AtomicUnsigned),
    /// Total bytes freed by cleanup operations (atomic).
    bytesFreed: std.atomic.Value(Constants.AtomicUnsigned),
    /// Total bytes saved by compression (atomic).
    bytesSaved: std.atomic.Value(Constants.AtomicUnsigned),
    /// Last run time in milliseconds (atomic).
    lastRunTime: std.atomic.Value(i64),
    /// Scheduler start time for uptime calculation (atomic).
    startTime: std.atomic.Value(i64),
};
```

#### SchedulerStats Helper Methods

| Method | Return Type | Description |
|--------|-------------|-------------|
| `successRate()` | `f64` | Task success rate (0.0 - 1.0) |
| `failureRate()` | `f64` | Task failure rate (0.0 - 1.0) |
| `hasFailures()` | `bool` | Returns `true` if any tasks have failed |
| `getExecuted()` | `u64` | Total tasks executed as u64 |
| `getFailed()` | `u64` | Total tasks failed as u64 |
| `getFilesCleaned()` | `u64` | Total files cleaned as u64 |
| `getFilesCompressed()` | `u64` | Total files compressed as u64 |
| `getBytesFreed()` | `u64` | Total bytes freed as u64 |
| `getBytesSaved()` | `u64` | Total bytes saved by compression as u64 |
| `uptimeSeconds()` | `i64` | Uptime in seconds since scheduler started |
| `tasksPerHour()` | `f64` | Average tasks executed per hour |
| `compressionRatio()` | `f64` | Compression savings ratio (bytes saved / total) |

#### Usage Example

```zig
const stats = scheduler.getStats();

// Check success/failure rates
const success = stats.successRate();  // e.g., 0.95 (95%)
const failure = stats.failureRate();  // e.g., 0.05 (5%)

// Check for failures
if (stats.hasFailures()) {
    std.log.warn("Scheduler has {d} failed tasks", .{stats.getFailed()});
}

// Get uptime info
const uptime = stats.uptimeSeconds();
const rate = stats.tasksPerHour();
std.log.info("Running for {d}s, {d:.2} tasks/hour", .{uptime, rate});

// Check cleanup efficiency
const freed = stats.getBytesFreed();
const saved = stats.getBytesSaved();
const ratio = stats.compressionRatio();
std.log.info("Freed {d} bytes, saved {d} bytes ({d:.1}% compression)", .{
    freed, saved, ratio * 100.0
});
```

## Methods

### init

Create a new scheduler.

**Alias:** `create`

```zig
pub fn init(allocator: std.mem.Allocator) !*Scheduler
```

### initWithIo

Create a new scheduler with an explicit `std.Io` handle.

```zig
pub fn initWithIo(allocator: std.mem.Allocator, io_handle: std.Io) !*Scheduler
```

### initWithThreadPool

Create a new scheduler that uses a thread pool for task execution (inheriting the pool's I/O handle).

```zig
pub fn initWithThreadPool(allocator: std.mem.Allocator, threadPool: *ThreadPool) !*Scheduler
```

**Parameters:**

* `allocator`: Memory allocator
* `threadPool`: Shared thread pool instance

### initFromConfig

Create a scheduler from global configuration using default I/O.

```zig
pub fn initFromConfig(allocator: std.mem.Allocator, config: SchedulerConfig, logsPath: ?[]const u8) !*Scheduler
```

### initFromConfigWithIo

Create a scheduler from global configuration with an explicit `std.Io` handle.

```zig
pub fn initFromConfigWithIo(allocator: std.mem.Allocator, io_handle: std.Io, config: SchedulerConfig, logsPath: ?[]const u8) !*Scheduler
```

### deinit

Clean up resources and stop the scheduler.

```zig
pub fn deinit(self: *Scheduler) void
```

### start

Start the scheduler worker thread.

```zig
pub fn start(self: *Scheduler) !void
```

### stop

Stop the scheduler gracefully, waiting for pending tasks to complete (with timeout).

```zig
pub fn stop(self: *Scheduler) void
```

### addTask

Add a scheduled task.

```zig
pub fn addTask(self: *Scheduler, name: []const u8, taskType: TaskType, schedule: Schedule, config: ScheduledTask.TaskConfig) !usize
```

**Parameters:**

* `name`: Unique task identifier
* `taskType`: Type of task
* `schedule`: Execution schedule
* `config`: Task configuration

**Returns:** Index of the added task

### setTaskPriority

Set the execution priority for a task.

```zig
pub fn setTaskPriority(self: *Scheduler, index: usize, priority: ScheduledTask.Priority) void
```

### setTaskRetryPolicy

Configure retry behavior for a task.

```zig
pub fn setTaskRetryPolicy(self: *Scheduler, index: usize, policy: ScheduledTask.RetryPolicy) void
```

### setTaskDependency

Set a dependency for a task (it will only run if the dependency is running).

```zig
pub fn setTaskDependency(self: *Scheduler, index: usize, dependencyName: []const u8) !void
```

### taskIndexByName

Find a task index by its name.

```zig
pub fn taskIndexByName(self: *Scheduler, name: []const u8) ?usize
```

### getTaskSnapshot

Returns immutable task state snapshot by task index.

```zig
pub fn getTaskSnapshot(self: *Scheduler, index: usize) ?TaskSnapshot
```

### getTaskSnapshotByName

Returns immutable task state snapshot by task name.

```zig
pub fn getTaskSnapshotByName(self: *Scheduler, name: []const u8) ?TaskSnapshot
```

### hasTaskNamed

Check whether a task with this name exists.

```zig
pub fn hasTaskNamed(self: *Scheduler, name: []const u8) bool
```

### setTaskEnabledByName

Enable or disable task by task name.

```zig
pub fn setTaskEnabledByName(self: *Scheduler, name: []const u8, enabled: bool) bool
```

Returns `true` when task exists and was updated.

### removeTaskByName

Remove task by name.

```zig
pub fn removeTaskByName(self: *Scheduler, name: []const u8) bool
```

Returns `true` when task existed and was removed.

### enabledTaskCount

Get number of enabled tasks.

```zig
pub fn enabledTaskCount(self: *Scheduler) usize
```

### runningTaskCount

Get number of tasks currently running.

```zig
pub fn runningTaskCount(self: *Scheduler) usize
```

### readyTaskCount

Get number of tasks currently ready to run (time/dependency/resource checks passed).

```zig
pub fn readyTaskCount(self: *Scheduler) usize
```

### nextRunInMs

Get remaining milliseconds until next run for a task index.

```zig
pub fn nextRunInMs(self: *Scheduler, index: usize) ?i64
```

### nextRunInMsByName

Get remaining milliseconds until next run by task name.

```zig
pub fn nextRunInMsByName(self: *Scheduler, name: []const u8) ?i64
```

### setTaskSchedule

Update schedule for a task and recalculate next-run timestamp.

```zig
pub fn setTaskSchedule(self: *Scheduler, index: usize, schedule: Schedule) bool
```

### rescheduleNow

Force a task to become runnable on next scheduler pass.

```zig
pub fn rescheduleNow(self: *Scheduler, index: usize) bool
```

### getDiskUsage

Get current disk usage percentage for a path.

```zig
pub fn getDiskUsage(self: *Scheduler, path: []const u8) !u8
```

### getFreeSpace

Get free space in bytes for a path.

```zig
pub fn getFreeSpace(self: *Scheduler, path: []const u8) !u64
```

### removeTask

Remove a task by index.

```zig
pub fn removeTask(self: *Scheduler, index: usize) !void
```

### enableTask

Enable a task by index.

```zig
pub fn enableTask(self: *Scheduler, index: usize) void
```

### disableTask

Disable a task by index.

```zig
pub fn disableTask(self: *Scheduler, index: usize) void
```

### runTaskNow

Execute a task immediately.

```zig
pub fn runTaskNow(self: *Scheduler, index: usize) !void
```

### runNowByName

Run task immediately by task name.

```zig
pub fn runNowByName(self: *Scheduler, name: []const u8) !bool
```

Returns `true` when task exists and was executed.

### getStats

Get current scheduler statistics.

```zig
pub fn getStats(self: *const Scheduler) SchedulerStats
```

### pause

Pauses background execution of all tasks. Tasks will not be executed until unpaused.

```zig
pub fn pause(self: *Scheduler) void
```

### unpause

Resumes background execution of tasks.

```zig
pub fn unpause(self: *Scheduler) void
```

### isPaused

Check if the scheduler is currently paused.

```zig
pub fn isPaused(self: *const Scheduler) bool
```

### resetStats

Reset all scheduler statistics to zero.

```zig
pub fn resetStats(self: *Scheduler) void
```

### setTelemetry

Set the telemetry instance for distributed tracing. When enabled, task executions create spans for observability.

```zig
pub fn setTelemetry(self: *Scheduler, telemetry: *Telemetry) void
```

**Parameters:**

* `telemetry`: Telemetry instance for tracing

### clearTelemetry

Disable telemetry tracing.

```zig
pub fn clearTelemetry(self: *Scheduler) void
```

### listTasks

Get list of all scheduled tasks.

```zig
pub fn listTasks(self: *const Scheduler) []const ScheduledTask
```

## Usage Example

```zig
const std = @import("std");
const logly = @import("logly");
const Scheduler = logly.Scheduler;
const SchedulerPresets = logly.SchedulerPresets;

pub fn main() !void {
    var gpa = std.heap.DebugAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Create scheduler
    var scheduler = try Scheduler.init(allocator);
    defer scheduler.deinit();

    // Add daily cleanup task using Presets
     _ = try scheduler.addTask(
        "log_cleanup",
        .cleanup,
        SchedulerPresets.dailyAt(2, 30), // Daily at 2:30 AM
        SchedulerPresets.dailyCleanup("logs", 30), // Config helper
    );

    // Add hourly compression manually
     _ = try scheduler.addTask(
        "log_compression",
        .compression,
        .{ .interval = 3600 * 1000 }, // Every hour (ms)
        .{
            .path = "logs",
            .minAgeSeconds = 3600, // Compress files older than 1 hour
            .filePattern = "*.log",
        },
    );

    // Start scheduler
    try scheduler.start();
    defer scheduler.stop();

    // Check stats periodically
    const stats = scheduler.getStats();
    std.debug.print("Tasks executed: {d}\n", .{
        stats.getExecuted(),
    });
}
```

## Aliases

The Scheduler module provides convenience aliases:

| Alias | Method |
|-------|--------|
| `begin` | `start` |
| `end` | `stop` |
| `halt` | `stop` |
| `statistics` | `getStats` |

## Additional State Methods

* `taskCount() usize` - Returns number of scheduled tasks
* `isRunning() bool` - Returns true if scheduler is running
* `hasTasks() bool` - Returns true if any tasks are scheduled

## SchedulerPresets

Helper functions for creating common schedules and task configurations.

### Schedule Presets

| Method | Description |
|--------|-------------|
| `hourlyCompression()` | Compression every hour |
| `everyMinutes(n)` | Every N minutes |
| `every15Minutes()` | Every 15 minutes (v0.1.8+) |
| `every30Minutes()` | Every 30 minutes |
| `every6Hours()` | Every 6 hours |
| `every12Hours()` | Every 12 hours |
| `dailyAt(hour, minute)` | Daily at specific time |
| `dailyMidnight()` | Daily at midnight |
| `dailyMaintenance()` | Daily at 2 AM |
| `weeklyCleanup()` | Weekly on Sunday at 2 AM |
| `onceAfter(seconds)` | Once after delay (v0.1.8+) |
| `healthCheckSchedule()` | Every 5 minutes (v0.1.8+) |
| `metricsSchedule()` | Every minute (v0.1.8+) |

### Task Config Presets

| Method | Description |
|--------|-------------|
| `dailyCleanup(path, days)` | Delete logs older than N days |
| `compressThenDelete(path, days)` | Compress then delete originals |
| `compressAndKeep(path, days)` | Compress, keep both versions |
| `compressOnly(path, days)` | Compress only, never delete |
| `archiveOldLogs(path, compress_days, delete_days)` | Archive with age limits |
| `aggressiveCleanup(path, days, maxFiles)` | Compress + file count limit |
| `hourlyArchive(path)` | Compress files older than 1 day (v0.1.8+) |
| `compressOnRotation(path)` | Compress just-rotated files (v0.1.8+) |
| `sizeBasedCompression(path, bytes)` | Compress when size exceeds threshold (v0.1.8+) |
| `diskUsageTriggered(path, percent)` | Compress when disk usage high (v0.1.8+) |
| `lowDiskSpaceTriggered(path, minFree)` | Compress when disk space low (v0.1.8+) |
| `recursiveCompression(path, days)` | Recursive directory compression (v0.1.8+) |

```zig
pub const SchedulerPresets = struct {
    // Schedules
    pub fn hourlyCompression() Schedule;
    pub fn everyMinutes(n: u64) Schedule;
    pub fn every15Minutes() Schedule;          // v0.1.8+
    pub fn every30Minutes() Schedule;
    pub fn every6Hours() Schedule;
    pub fn every12Hours() Schedule;
    pub fn dailyAt(hour: u8, minute: u8) Schedule;
    pub fn dailyMidnight() Schedule;
    pub fn dailyMaintenance() Schedule;
    pub fn weeklyCleanup() Schedule;
    pub fn onceAfter(seconds: u64) Schedule;   // v0.1.8+
    pub fn healthCheckSchedule() Schedule;     // v0.1.8+
    pub fn metricsSchedule() Schedule;         // v0.1.8+

    // Task Configurations
    pub fn dailyCleanup(path: []const u8, maxAgeDays: u64) TaskConfig;
    pub fn compressThenDelete(path: []const u8, minAgeDays: u64) TaskConfig;
    pub fn compressAndKeep(path: []const u8, minAgeDays: u64) TaskConfig;
    pub fn compressOnly(path: []const u8, minAgeDays: u64) TaskConfig;
    pub fn archiveOldLogs(path: []const u8, compress_days: u64, delete_days: u64) TaskConfig;
    pub fn aggressiveCleanup(path: []const u8, maxAgeDays: u64, maxFiles: usize) TaskConfig;
    pub fn hourlyArchive(path: []const u8) TaskConfig;             // v0.1.8+
    pub fn compressOnRotation(path: []const u8) TaskConfig;        // v0.1.8+
    pub fn sizeBasedCompression(path: []const u8, bytes: u64) TaskConfig;  // v0.1.8+
    pub fn diskUsageTriggered(path: []const u8, percent: u8) TaskConfig;   // v0.1.8+
    pub fn lowDiskSpaceTriggered(path: []const u8, minFree: u64) TaskConfig;  // v0.1.8+
    pub fn recursiveCompression(path: []const u8, days: u64) TaskConfig;   // v0.1.8+
};
```

## See Also

* [Compression API](compression.md) - Log compression
* [Rotation Guide](../guide/rotation.md) - Log rotation
* [Configuration Guide](../guide/configuration.md) - Full configuration options
* [Telemetry API](telemetry.md) - Distributed tracing integration

## Telemetry Integration

The scheduler supports optional telemetry integration for distributed tracing. When enabled, each task execution creates a span with relevant attributes.

### Setup

```zig
const logly = @import("logly");

// Create telemetry instance
var telemetry = try logly.Telemetry.init(allocator, .{
    .provider = .file,
    .exporterFilePath = "telemetry_spans.jsonl",
});
defer telemetry.deinit();

// Create scheduler with telemetry
var scheduler = try logly.Scheduler.init(allocator);
defer scheduler.deinit();

scheduler.setTelemetry(&telemetry);
```

### Span Attributes

Task execution spans include the following attributes:

| Attribute | Type | Description |
|-----------|------|-------------|
| `task.type` | string | Task type (cleanup, compression, etc.) |
| `task.priority` | string | Task priority level |
| `task.durationMs` | integer | Execution duration in milliseconds |
| `cleanup.filesDeleted` | integer | Files deleted (cleanup tasks) |
| `cleanup.bytesFreed` | integer | Bytes freed (cleanup tasks) |
| `compression.files` | integer | Files compressed (compression tasks) |
| `compression.bytesSaved` | integer | Bytes saved (compression tasks) |
| `health.healthy` | boolean | Health status (healthCheck tasks) |
| `metrics.logCount` | integer | Log count (metricsSnapshot tasks) |
| `metrics.errorCount` | integer | Error count (metricsSnapshot tasks) |

### Telemetry Metrics

The scheduler also records counter and gauge metrics:

* `scheduler.tasksExecuted` (counter): Incremented for each task execution
* `scheduler.task_duration_ms` (gauge): Task execution duration

### Example Output

```json
{
  "trace_id": "abc123...",
  "span_id": "def456...",
  "name": "log_cleanup",
  "kind": "internal",
  "status": "ok",
  "start_time": 1704067200000000000,
  "end_time": 1704067200500000000,
  "attributes": {
    "task.type": "cleanup",
    "task.priority": "normal",
    "task.duration_ms": 500,
    "cleanup.files_deleted": 5,
    "cleanup.bytes_freed": 1048576
  }
}
```
