Skip to main content

pipedash_core/domain/
run_logs.rs

1use chrono::{
2    DateTime,
3    Utc,
4};
5pub use pipedash_plugin_api::{
6    LineMarker,
7    LogAvailability,
8    LogDialect,
9    LogNodeKind,
10    LogSink,
11    ParsedLine,
12    PlainDialect,
13};
14use serde::{
15    Deserialize,
16    Serialize,
17};
18
19use super::pipeline::PipelineStatus;
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct LogNode {
23    pub id: String,
24    pub parent_id: Option<String>,
25    pub kind: LogNodeKind,
26    pub name: String,
27    pub status: PipelineStatus,
28    pub started_at: Option<DateTime<Utc>>,
29    pub finished_at: Option<DateTime<Utc>>,
30    pub log: Option<LogAvailability>,
31    pub web_url: Option<String>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct RunLogTree {
36    pub nodes: Vec<RunLogNode>,
37    pub default_node_id: Option<String>,
38    pub complete: bool,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct RunLogNode {
43    pub id: String,
44    pub parent_id: Option<String>,
45    pub kind: LogNodeKind,
46    pub name: String,
47    pub status: PipelineStatus,
48    pub started_at: Option<DateTime<Utc>>,
49    pub finished_at: Option<DateTime<Utc>>,
50    pub duration_seconds: Option<i64>,
51    pub log: Option<LogAvailability>,
52    pub web_url: Option<String>,
53    pub depth: u8,
54    pub navigable: bool,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58#[serde(tag = "state", rename_all = "snake_case")]
59pub enum RunLogDocument {
60    Ready(LogDocumentMeta),
61    Loading { received_bytes: u64 },
62    Pending,
63    Unavailable { message: String },
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct LogDocumentMeta {
68    pub node_id: String,
69    pub revision: i64,
70    pub complete: bool,
71    pub truncated: bool,
72    pub line_count: u32,
73    pub text_bytes: u64,
74    pub first_timestamp_ms: Option<i64>,
75    pub styles: Vec<LogStyle>,
76    pub sections: Vec<LogSection>,
77    pub error_lines: Vec<u32>,
78    pub warning_lines: Vec<u32>,
79    pub error_total: u32,
80    pub warning_total: u32,
81    pub focus_line: Option<u32>,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
85#[serde(rename_all = "lowercase")]
86pub enum LogSectionKind {
87    Step,
88    Group,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct LogSection {
93    pub id: u32,
94    pub parent: Option<u32>,
95    pub kind: LogSectionKind,
96    pub node_id: Option<String>,
97    pub title: String,
98    pub status: Option<PipelineStatus>,
99    pub duration_ms: Option<i64>,
100    pub header_line: Option<u32>,
101    pub start_line: u32,
102    pub end_line: u32,
103    pub error_count: u32,
104    pub open: bool,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
108pub struct LogStyle {
109    pub fg: Option<AnsiColor>,
110    pub bg: Option<AnsiColor>,
111    pub bold: bool,
112    pub dim: bool,
113    pub italic: bool,
114    pub underline: bool,
115    pub strike: bool,
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
119#[serde(rename_all = "lowercase")]
120pub enum AnsiColor {
121    Black,
122    Red,
123    Green,
124    Yellow,
125    Blue,
126    Magenta,
127    Cyan,
128    White,
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
132#[serde(rename_all = "lowercase")]
133#[repr(u8)]
134pub enum LineKind {
135    #[default]
136    Plain = 0,
137    Group = 1,
138    Error = 2,
139    Warning = 3,
140    Notice = 4,
141    Debug = 5,
142    Command = 6,
143}
144
145impl LineKind {
146    pub fn is_plain(&self) -> bool {
147        *self == LineKind::Plain
148    }
149
150    pub fn from_u8(value: u8) -> Option<Self> {
151        Some(match value {
152            0 => LineKind::Plain,
153            1 => LineKind::Group,
154            2 => LineKind::Error,
155            3 => LineKind::Warning,
156            4 => LineKind::Notice,
157            5 => LineKind::Debug,
158            6 => LineKind::Command,
159            _ => return None,
160        })
161    }
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct LogLinesPage {
166    pub start: u32,
167    pub lines: Vec<LogLine>,
168}
169
170fn is_zero(value: &u32) -> bool {
171    *value == 0
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
175pub struct LogLine {
176    pub text: String,
177    #[serde(default, skip_serializing_if = "LineKind::is_plain")]
178    pub kind: LineKind,
179    #[serde(default, skip_serializing_if = "Option::is_none")]
180    pub ts: Option<i64>,
181    #[serde(default, skip_serializing_if = "Vec::is_empty")]
182    pub spans: Vec<(u32, u32, u16)>,
183    #[serde(default, skip_serializing_if = "is_zero")]
184    pub omitted: u32,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct LogSearchQuery {
189    pub text: String,
190    pub regex: bool,
191    pub case_sensitive: bool,
192}
193
194#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
195pub struct LogSearchResult {
196    pub matches: Vec<(u32, u32, u32)>,
197    pub total: u64,
198    pub capped: bool,
199}
200
201#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
202pub struct LogCacheStats {
203    pub bytes: u64,
204    pub runs: u64,
205}