syntax = "proto3";

package rs.tokio.console.tasks;

import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
import "common.proto";

// A task state update.
//
// Each `TaskUpdate` contains any task data that has changed since the last
// update. This includes:
// - any new tasks that were spawned since the last update
// - the current stats for any task whose stats changed since the last update
message TaskUpdate {
    // A list of new tasks that were spawned since the last `TaskUpdate` was
    // sent.
    //
    // If this is empty, no new tasks were spawned.
    repeated Task new_tasks = 1;
    // Any task stats that have changed since the last update.
    //
    // This is a map of task IDs (64-bit unsigned integers) to task stats. If a
    // task's ID is not included in this map, then its stats have *not* changed
    // since the last `TaskUpdate` in which they were present. If a task's ID
    // *is* included in this map, the corresponding value represents a complete
    // snapshot of that task's stats at in the current time window.
    map<uint64, Stats> stats_update = 3;
    // A count of how many task events (e.g. polls, spawns, etc) were not
    // recorded because the application's event buffer was at capacity.
    //
    // If everything is working normally, this should be 0. If it is greater
    // than 0, that may indicate that some data is missing from this update, and
    // it may be necessary to increase the number of events buffered by the
    // application to ensure that data loss is avoided.
    //
    // If the application's instrumentation ensures reliable delivery of events,
    // this will always be 0.
    uint64 dropped_events = 4;
}

// A task details update
message TaskDetails {
    // The task's ID which the details belong to.
    common.Id task_id = 1;

    // The timestamp for when the update to the task took place.
    google.protobuf.Timestamp now = 2;

    // A histogram of task poll durations.
    //
    // This is either:
    // - the raw binary representation of a HdrHistogram.rs `Histogram`
    //   serialized to binary in the V2 format (legacy)
    // - a binary histogram plus details on outliers (current)
    oneof poll_times_histogram {
        // HdrHistogram.rs `Histogram` serialized to binary in the V2 format
        bytes legacy_histogram = 3;
        // A histogram plus additional data.
        DurationHistogram histogram = 4;
    }

    // A histogram of task scheduled durations.
    //
    // The scheduled duration is the time a task spends between being
    // woken and when it is next polled.
    DurationHistogram scheduled_times_histogram = 5;
}

// Data recorded when a new task is spawned.
message Task {
    // The task's ID.
    //
    // This uniquely identifies this task across all *currently live* tasks.
    // When the task's stats change, or when the task completes, it will be
    // identified by this ID; if the client requires additional information
    // included in the `Task` message, it should store that data and access it
    // by ID.
    common.Id id = 1;
    // The numeric ID of the task's `Metadata`.
    //
    // This identifies the `Metadata` that describes the `tracing` span
    // corresponding to this task. The metadata for this ID will have been sent
    // in a prior `RegisterMetadata` message.
    common.MetaId metadata = 2;
    // The category of task this task belongs to.
    Kind kind = 3;

    // A list of `Field` objects attached to this task.
    repeated common.Field fields = 4;

    // An ordered list of span IDs corresponding to the `tracing` span context
    // in which this task was spawned.
    //
    // The first span ID in this list is the immediate parent, followed by that
    // span's parent, and so on. The final ID is the root span of the current
    // trace.
    //
    // If this is empty, there were *no* active spans when the task was spawned.
    //
    // These IDs may correspond to `tracing` spans which are *not* tasks, if
    // additional trace data is being collected.
    repeated common.SpanId parents = 5;
    // The location in code where the task was spawned.
    common.Location location = 6;

    // The category of task this task belongs to.
    enum Kind {
        // A task spawned using a runtime's standard asynchronous task spawning
        // operation (such as `tokio::task::spawn`).
        SPAWN = 0;
        // A task spawned via a runtime's blocking task spawning operation
        // (such as `tokio::task::spawn_blocking`).
        BLOCKING = 1;
    }

}

// Task performance statistics.
message Stats {
    // Timestamp of when the task was spawned.
    google.protobuf.Timestamp created_at = 1;
    // Timestamp of when the task was dropped.
    google.protobuf.Timestamp dropped_at = 2;
    // The total number of times this task has been woken over its lifetime.
    uint64 wakes = 3;
    // The total number of times this task's waker has been cloned.
    uint64 waker_clones = 4;
    // The total number of times this task's waker has been dropped.
    uint64 waker_drops = 5;
    // The timestamp of the most recent time this task has been woken.
    //
    // If this is `None`, the task has not yet been woken.
    optional google.protobuf.Timestamp last_wake = 6;
    // Contains task poll statistics.
    common.PollStats poll_stats = 7;
    // The total number of times this task has woken itself.
    uint64 self_wakes = 8;
    // The total duration this task was scheduled prior to being polled, summed
    // across all poll cycles.
    //
    // Note that this includes only polls that have started, and does not
    // reflect any scheduled state where the task hasn't yet been polled.
    // Subtracting both `busy_time` (from the task's `PollStats`) and
    // `scheduled_time` from the total lifetime of the task results in the
    // amount of time it spent unable to progress because it was waiting on 
    // some resource.
    google.protobuf.Duration scheduled_time = 9;
}


message DurationHistogram {

    // HdrHistogram.rs `Histogram` serialized to binary in the V2 format
    bytes raw_histogram = 1;

    // The histogram's maximum value.
    uint64 max_value = 2;

    // The number of outliers which have exceeded the histogram's maximum value.
    uint64 high_outliers = 3;

    // The highest recorded outlier. This is only present if `high_outliers` is
    // greater than zero.
    optional uint64 highest_outlier = 4;

}