1
- mod event;
2
- mod log_event;
1
+ mod encoding;
2
+ mod log;
3
+ mod notification;
4
+ mod output;
3
5
4
- use event :: Event ;
6
+ use output :: OutputEventsPayload ;
5
7
6
8
use crate :: { api:: tap:: TapSink , topology:: WatchRx } ;
7
9
8
- use async_graphql:: { validators:: IntRange , Context , Subscription } ;
10
+ use async_graphql:: { validators:: IntRange , Context , Enum , Subscription } ;
9
11
use futures:: StreamExt ;
10
12
use itertools:: Itertools ;
11
13
use rand:: { rngs:: SmallRng , Rng , SeedableRng } ;
12
14
use tokio:: { select, stream:: Stream , sync:: mpsc, time} ;
13
15
16
+ #[ derive( Enum , Copy , Clone , PartialEq , Eq ) ]
17
+ /// Encoding format for the event
18
+ pub enum EventEncodingType {
19
+ Json ,
20
+ Yaml ,
21
+ }
22
+
14
23
#[ derive( Debug , Default ) ]
15
24
pub struct EventsSubscription ;
16
25
@@ -23,7 +32,7 @@ impl EventsSubscription {
23
32
component_names : Vec < String > ,
24
33
#[ graphql( default = 500 ) ] interval : u32 ,
25
34
#[ graphql( default = 100 , validator( IntRange ( min = "1" , max = "10_000" ) ) ) ] limit : u32 ,
26
- ) -> impl Stream < Item = Vec < Event > > + ' a {
35
+ ) -> impl Stream < Item = Vec < OutputEventsPayload > > + ' a {
27
36
let watch_rx = ctx. data_unchecked :: < WatchRx > ( ) . clone ( ) ;
28
37
29
38
// Client input is confined to `u32` to provide sensible bounds.
@@ -39,15 +48,15 @@ fn create_events_stream(
39
48
component_names : Vec < String > ,
40
49
interval : u64 ,
41
50
limit : usize ,
42
- ) -> impl Stream < Item = Vec < Event > > {
51
+ ) -> impl Stream < Item = Vec < OutputEventsPayload > > {
43
52
// Channel for receiving individual tap payloads. Since we can process at most `limit` per
44
53
// interval, this is capped to the same value.
45
54
let ( tap_tx, mut tap_rx) = mpsc:: channel ( limit) ;
46
55
47
56
// The resulting vector of `Event` sent to the client. Only one result set will be streamed
48
57
// back to the client at a time. This value is set higher than `1` to prevent blocking the event
49
58
// pipeline on slower client connections, but low enough to apply a modest cap on mem usage.
50
- let ( mut event_tx, event_rx) = mpsc:: channel :: < Vec < Event > > ( 10 ) ;
59
+ let ( mut event_tx, event_rx) = mpsc:: channel :: < Vec < OutputEventsPayload > > ( 10 ) ;
51
60
52
61
tokio:: spawn ( async move {
53
62
// Create a tap sink. When this drops out of scope, clean up will be performed on the
@@ -58,14 +67,14 @@ fn create_events_stream(
58
67
let mut interval = time:: interval ( time:: Duration :: from_millis ( interval) ) ;
59
68
60
69
// Temporary structure to hold sortable values of `Event`.
61
- struct SortableEvent {
70
+ struct SortableOutputEventsPayload {
62
71
batch : usize ,
63
- event : Event ,
72
+ payload : OutputEventsPayload ,
64
73
}
65
74
66
75
// Collect a vector of results, with a capacity of `limit`. As new `Event`s come in,
67
76
// they will be sampled and added to results.
68
- let mut results = Vec :: < SortableEvent > :: with_capacity ( limit) ;
77
+ let mut results = Vec :: < SortableOutputEventsPayload > :: with_capacity ( limit) ;
69
78
70
79
// Random number generator to allow for sampling. Speed trumps cryptographic security here.
71
80
// The RNG must be Send + Sync to use with the `select!` loop below, hence `SmallRng`.
@@ -80,32 +89,32 @@ fn create_events_stream(
80
89
// Process `TapPayload`s. A tap payload could contain log/metric events or a
81
90
// notification. Notifications are emitted immediately; events buffer until
82
91
// the next `interval`.
83
- Some ( event ) = tap_rx. next( ) => {
84
- let event = event . into( ) ;
92
+ Some ( payload ) = tap_rx. next( ) => {
93
+ let payload = payload . into( ) ;
85
94
86
95
// Emit notifications immediately; these don't count as a 'batch'.
87
- if let Event :: Notification ( _) = event {
96
+ if let OutputEventsPayload :: Notification ( _) = payload {
88
97
// If an error occurs when sending, the subscription has likely gone
89
98
// away. Break the loop to terminate the thread.
90
- if let Err ( err) = event_tx. send( vec![ event ] ) . await {
99
+ if let Err ( err) = event_tx. send( vec![ payload ] ) . await {
91
100
debug!( message = "Couldn't send notification." , error = ?err) ;
92
101
break ;
93
102
}
94
103
} else {
95
104
// Wrap tap in a 'sortable' wrapper, using the batch as a key, to
96
105
// re-sort after random eviction.
97
- let event = SortableEvent { batch, event } ;
106
+ let payload = SortableOutputEventsPayload { batch, payload } ;
98
107
99
108
// A simple implementation of "Algorithm R" per
100
109
// https://en.wikipedia.org/wiki/Reservoir_sampling. As we're unable to
101
110
// pluck the nth result, this is chosen over the more optimal "Algorithm L"
102
111
// since discarding results isn't an option.
103
112
if limit > results. len( ) {
104
- results. push( event ) ;
113
+ results. push( payload ) ;
105
114
} else {
106
115
let random_number = rng. gen_range( 0 ..batch) ;
107
116
if random_number < results. len( ) {
108
- results[ random_number] = event ;
117
+ results[ random_number] = payload ;
109
118
}
110
119
}
111
120
// Increment the batch count, to be used for the next Algo R loop.
@@ -123,7 +132,7 @@ fn create_events_stream(
123
132
let results = results
124
133
. drain( ..)
125
134
. sorted_by_key( |r| r. batch)
126
- . map( |r| r. event )
135
+ . map( |r| r. payload )
127
136
. collect( ) ;
128
137
129
138
// If we get an error here, it likely means that the subscription has
0 commit comments