-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathworkflow.proto
More file actions
455 lines (375 loc) · 18.4 KB
/
workflow.proto
File metadata and controls
455 lines (375 loc) · 18.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
// api - bitdrift's client/server API definitions
// Copyright Bitdrift, Inc. All rights reserved.
//
// Use of this source code and APIs are governed by a source available license that can be found in
// the LICENSE file or at:
// https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt
syntax = "proto3";
package bitdrift_public.protobuf.workflow.v1;
import "bitdrift_public/protobuf/matcher/v1/log_matcher.proto";
import "bitdrift_public/protobuf/state/v1/matcher.proto";
import "bitdrift_public/protobuf/state/v1/scope.proto";
import "validate/validate.proto";
// The wrapper for the list of workflows. Top-level item used to send information
// about workflows from server to all connected clients.
message WorkflowsConfiguration {
// An optional list of workflows.
repeated Workflow workflows = 1;
}
// A complete workflow configuration. Each traversal of the state machine defined
// by the configuration is called a *workflow run*. There can be multiple runs
// for a given workflow configuration active at a given time on a given device.
message Workflow {
// String that describes this workflow uniquely. This is is guaranteed to be unique.
string id = 1 [(validate.rules).string = {min_len: 1}];
// A list of states the workflow may transition through.
// Notes:
// * The initial state is the first state in the list.
// * The final state(s) is identified by not having any transitions.
repeated State states = 2 [(validate.rules).repeated = {min_items: 1}];
// The execution type. Affects the number of workflow *runs* created
// for a given workflow.
Execution execution = 3;
// A matched logs count limit that's tracked for each of the workflow *runs* separately.
// The run is removed if it reaches the match limit.
LimitMatchedLogsCount limit_matched_logs_count = 4;
// A duration limit that's tracked for each of the workflow *runs* separately.
// The run is removed if the time spent on it reaches the duration.
LimitDuration limit_duration = 5;
// Represents a single step in a given workflow.
message State {
// An identifier that's unique within given workflow' state identifiers.
string id = 1 [(validate.rules).string = {min_len: 1}];
// An optional array of transitions that can be taken from a given state.
// No array or empty array of transitions means that the state is a final state.
repeated Transition transitions = 2;
// An optional timeout transition that will occur if no transition occurs before the specified
// timeout. The timeout is persisted across app restarts in the workflow state.
TransitionTimeout timeout = 3;
}
message TransitionTimeout {
// The identifier of the state to transition to.
string target_state_id = 1 [(validate.rules).string = {min_len: 1}];
uint64 timeout_ms = 2 [(validate.rules).uint64.gt = 0];
// An optional array of actions to be executed upon performing this transition.
repeated Action actions = 3;
}
// A transition used to describe the connection between two states. Specifies
// a rule for the change of state and provides actions that to be performed
// upon executing the transition.
//
// Provided rule is evaluated on the arrival of a log message.
message Transition {
// The identifier of the state to transition to.
string target_state_id = 1 [(validate.rules).string = {min_len: 1}];
// The guard that must be satisfied for this transition to be executed.
Rule rule = 2 [(validate.rules).message = {required: true}];
// An optional array of actions to be executed upon performing this transition.
repeated Action actions = 3;
// An optional array of extensions that act as configuration points for actions attached
// to the current transition or transitions further down the line.
repeated TransitionExtension extensions = 4;
}
// A predicate that must be satisfied for a transition to happen.
message Rule {
oneof rule_type {
option (validate.required) = true;
RuleLogMatch rule_log_match = 1;
RuleStateChangeMatch rule_state_change_match = 3;
}
reserved 2;
}
// An extra configuration for a given transition.
message TransitionExtension {
oneof extension_type {
option (validate.required) = true;
SankeyDiagramValueExtraction sankey_diagram_value_extraction = 1;
SaveTimestamp save_timestamp = 2;
SaveField save_field = 3;
}
// The timestamp of the transition will be snapped, and persisted to the workflow state. This
// can be looked up by ID by further transitions. The saved timestamp is fraction seconds since
// the Unix epoch.
message SaveTimestamp {
string id = 1;
}
// The log's field value, if available, will be snapped, and persisted to the workflow state.
// This can be looked up by ID by further transitions.
message SaveField {
string id = 1;
string field_name = 2;
}
// The configuration of a value extraction for a Sankey diagram.
message SankeyDiagramValueExtraction {
// The ID of the Sankey diagram to extract the value for.
string sankey_diagram_id = 1 [(validate.rules).string = {min_len: 1}];
// The name of the Sankey diagram state.
oneof value_type {
option (validate.required) = true;
// A fixed value.
string fixed = 2 [(validate.rules).string = {min_len: 1}];
// The value extracted from a field.
FieldExtracted field_extracted = 3;
}
// Whether extracting the value with the extension counts toward the limit of the extracted values
// defined on a given emit Sankey diagram action.
bool counts_toward_sankey_extraction_limit = 4;
}
}
// Rule used to transition based on a log.
message RuleLogMatch {
// The condition that a log must satisfy.
matcher.v1.LogMatcher log_matcher = 1 [(validate.rules).message = {required: true}];
// The number of times the condition needs to be met, default is 1.
uint32 count = 2 [(validate.rules).uint32.gt = 0];
}
// Matches against a state change. Every time the value of a scoped key changes (new value is different from previous value),
// the rule evaluates whether the previous and new values match the specified conditions.
message RuleStateChangeMatch {
// The scope of the state to watch for.
state.v1.StateScope scope = 1 [(validate.rules).enum.defined_only = true];
// The key of the state to watch for.
string key = 2 [(validate.rules).string = {min_len: 1}];
// The match condition which is applied to the previous value of the state during a state change.
state.v1.StateValueMatch previous_value = 3;
// The match condition which is applied to the new value of the state during a state change.
state.v1.StateValueMatch new_value = 4 [(validate.rules).message = {required: true}];
}
// An action to be taken when moving to a new state.
message Action {
oneof action_type {
option (validate.required) = true;
ActionFlushBuffers action_flush_buffers = 1;
ActionEmitMetric action_emit_metric = 2;
ActionEmitSankeyDiagram action_emit_sankey_diagram = 3;
ActionTakeScreenshot action_take_screenshot = 4;
ActionGenerateLog action_generate_log = 5;
}
// Generates a new log message. This log will be injected into the workflow engine and processed
// like any other log, either by this workflow or by another workflow.
message ActionGenerateLog {
// Describes how to obtain a value used in field composition.
message ValueReference {
oneof value_reference_type {
// Fixed value that never changes.
string fixed = 1;
// The value of the field from the current log.
string field_from_current_log = 2;
// The value of a field from a previous log, saved via the SaveField extension. This is
// the ID of the extension.
string saved_field_id = 3;
// The timestamp of a previous log, saved via the SaveTimestamp extension. This is the ID
// of the extension.
string saved_timestamp_id = 4;
// Fill the field with a UUID v4.
bool uuid = 5;
}
}
// A pair of values.
message ValueReferencePair {
ValueReference lhs = 1;
ValueReference rhs = 2;
}
// A field to be generated. Note that when operating on timestamps, the values are expected
// to be fractions of seconds since the Unix epoch.
message GeneratedField {
// The name of the field.
string name = 1;
// The value of the field.
oneof generated_field_value_type {
option (validate.required) = true;
// A single value.
ValueReference single = 2;
// Perform subtraction. lhs - rhs. Both values must be convertible to floating point.
ValueReferencePair subtract = 3;
// Perform addition. lhs + rhs. Both values must be convertible to floating point.
ValueReferencePair add = 4;
// Perform multiplication. lhs * rhs. Both values must be convertible to floating point.
ValueReferencePair multiply = 5;
// Perform division. lhs / rhs. Both values must be convertible to floating point.
ValueReferencePair divide = 6;
}
}
string message = 1;
repeated GeneratedField fields = 2;
// A unique identifier for the action. If multiple generate log actions have the same ID and
// are performed as the result of processing the same log, a client will emit only a single
// log as the result. This implies that the resulting logs in this case should be identical.
string id = 3;
// Should be one of the log types in buffer_log.fbs. If unset the default is 0 which is
// Normal.
uint32 log_type = 4;
}
// Flush the content of the specified buffer(s) to the bitdrift control plane, with the option to continue
// streaming logs incoming to the buffer(s) to remote services, until one of the specified termination
// conditions is met.
message ActionFlushBuffers {
// A streaming configuration to apply when buffer flushing occurs.
// Streaming is active from the time the flush of the specified buffers begins until whichever of
// the following happens first:
// * [required] The session ID changes
// * [optional, configurable] The maximum number of logs is reached
message Streaming {
// The criteria that can be used to terminate streaming.
message TerminationCriterion {
message LogsCount {
// The maximum number of logs that can be streamed.
uint64 max_logs_count = 1 [(validate.rules).uint64.gt = 0];
}
oneof type {
option (validate.required) = true;
LogsCount logs_count = 1;
}
}
// The IDs of *streaming* buffers to which logs should be redirected.
// If a specified buffer doesn't exist or isn't of a *streaming* type, logs are not redirected
// and will end up in the buffer(s) they were originally supposed to land in. Otherwise, they are
// redirected to all specified, existing destination streaming buffers.
// Starting with client configuration 11 and up: If no destination streaming buffers are specified,
// the logs are redirected to one of the existing continuous streaming buffers, if such a buffer
// exists.
repeated string destination_streaming_buffer_ids = 1;
// Additional termination criteria used to stop streaming. Apart from the criteria specified here,
// a change in session ID will also stop streaming.
repeated TerminationCriterion termination_criteria = 2;
}
// An optional array indicating which buffers should be flushed. An empty array or no array
// will flush all buffers.
repeated string buffer_ids = 1;
// An identifier used to match this action with a specific workflow rule. This should
// be included as the associated listener_ids in the matching log.
string id = 2 [(validate.rules).string = {min_len: 1}];
// The streaming configuration to apply when buffer flushing occurs. If not specified, no subsequent
// log streaming will occur when the specified buffers are flushed.
Streaming streaming = 3;
}
// Emit a synthetic metric.
message ActionEmitMetric {
// The ID of a metric. If multiple actions have them same ID and are performed
// as the result of processing the same event (i.e. log) a client performs only one
// of the actions. The client emit a stat with a name that follows
// the following format "workflow_actions::<ID>".
// As the identifier becomes a part of metric's name it must meet the requirements
// of prometheus metric name. In other words it needs to match
// regex "[a-zA-Z_][a-zA-Z0-9_]*".
string id = 1 [(validate.rules).string = {min_len: 1}];
// The type of metric.
oneof metric_type {
option (validate.required) = true;
// A counter.
Counter counter = 2;
// A histogram.
Histogram histogram = 5;
}
// The value that is added to the metric. For a counter the value is added to the counter, while for a histogram the value is recorded as a sample.
oneof value_extractor_type {
option (validate.required) = true;
// A fixed value.
uint32 fixed = 3;
// The value to add to the metric is extracted from a field in the log. If the field is not present or not convertible to a number, no metric is emitted.
FieldExtracted field_extracted = 6;
}
// The tags for the metric.
repeated Tag tags = 4;
// A synthetic counter.
message Counter {}
// A synthetic histogram.
message Histogram {}
}
// Emit data for Sankey diagram.
// The action requires at least one transition on the path to the action to have
// `SankeyDiagramValueExtraction` extension.
// Refer to `SankeyDiagramValueExtraction` to learn more about how the values
// for the Sankey diagram nodes are extracted.
message ActionEmitSankeyDiagram {
// The ID of a Sankey diagram. If multiple diagrams have them same ID and are performed
// as the result of processing the same event (i.e. log) a client performs only one
// of the actions. The client emit a stat with a name that follows
// the following format "workflow_actions::<ID>".
// As the identifier becomes a part of metric's name it must meet the requirements
// of prometheus metric name. In other words it needs to match
// regex "[a-zA-Z_][a-zA-Z0-9_]*".
string id = 1 [(validate.rules).string = {min_len: 1}];
// The maximum number of node values that can be extracted for a given Sankey diagram.
// Extracted values are kept in FIFO order, and once the limit is exceeded, the oldest ones
// are dropped to make space for new ones. A limit of 0 means this feature is effectively disabled,
// and all extracted values are retained.
//
// For any Sankey diagram and its paths, the limitation on values and the exclusion of extracted values
// does not apply to:
// * Transitions on the path from the START node to the first node with incoming backward-
// pointing transitions.
// * Transitions on the path from the last transition with two or more outgoing transitions to the END node.
//
// In the example below, values extracted for the A --> B and B --> END transitions are never dropped.
//
// ┌──┐
// ▼ │
// START --> A --> B --> C --> END -> Sankey
//
// For example, if the limit is set to three (3) and the above workflow encounters log-matching nodes in the
// following order: A -> B(1) -> B(2) -> B(3) -> B(4) -> B(5) -> C, the final Sankey diagram will show
// the values extracted from the following nodes sequence: A -> B(3) -> B(4) -> B(5) -> C.
uint32 limit = 2 [(validate.rules).uint32.gt = 0];
// Tags for a counter that is emitted when a Sankey diagram path is completed.
// Each completion of the path increments the counter by one.
repeated Tag tags = 3;
}
// Wraps a tag that is associated with the metric.
message Tag {
// The name of the tag.
string name = 1 [(validate.rules).string = {min_len: 1}];
oneof tag_type {
option (validate.required) = true;
// A fixed tag value.
string fixed_value = 2 [(validate.rules).string = {min_len: 1}];
// The tag value is extracted from a field in the log. If the field is not present, no tag is added.
FieldExtracted field_extracted = 3;
// The tag value is the body of the log. If the body is not present, no tag is added.
bool log_body_extracted = 4;
StateExtracted state_extracted = 6;
}
reserved 5;
reserved "feature_flag_extracted";
}
// Emit a log containing application screenshot.
message ActionTakeScreenshot {
reserved 1;
}
}
message Execution {
// An execution mode where a new workflow *run* starting from an initial
// state can be started only if there are no other active runs of a given workflow.
message ExecutionExclusive {}
oneof execution_type {
ExecutionExclusive execution_exclusive = 1;
}
reserved 2;
}
// A limit for the number of logs that a workflow run can match.
message LimitMatchedLogsCount {
uint32 count = 1 [(validate.rules).uint32.gt = 0];
}
// A limit for the duration of time a given workflow run can stay active for.
// The time starts ticking when a given workflow run leaves its initial state.
message LimitDuration {
uint64 duration_ms = 2 [(validate.rules).uint64.gt = 0];
}
// A value extracted from log's field.
message FieldExtracted {
string field_name = 1 [(validate.rules).string = {min_len: 1}];
message Exact {}
// For now we only support exact match, but in the future we might support more complex
// extraction logic like regex captures. If not specified, the default is exact match.
oneof extraction_type {
Exact exact = 2;
}
}
message StateExtracted {
state.v1.StateScope scope = 1 [(validate.rules).enum.defined_only = true];
string key = 2 [(validate.rules).string = {min_len: 1}];
oneof extraction_type {
Exact exact = 2;
}
}
}