openc3 5.2.0 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of openc3 might be problematic. Click here for more details.

Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/bin/openc3cli +108 -105
  3. data/data/config/interface_modifiers.yaml +22 -4
  4. data/data/config/item_modifiers.yaml +4 -2
  5. data/data/config/microservice.yaml +18 -0
  6. data/data/config/table_manager.yaml +2 -2
  7. data/data/config/tool.yaml +1 -1
  8. data/ext/openc3/ext/config_parser/config_parser.c +17 -2
  9. data/lib/openc3/api/api.rb +1 -0
  10. data/lib/openc3/api/interface_api.rb +12 -0
  11. data/lib/openc3/api/metrics_api.rb +97 -0
  12. data/lib/openc3/api/router_api.rb +14 -2
  13. data/lib/openc3/api/target_api.rb +24 -3
  14. data/lib/openc3/api/tlm_api.rb +5 -4
  15. data/lib/openc3/config/config_parser.rb +29 -4
  16. data/lib/openc3/core_ext/time.rb +6 -1
  17. data/lib/openc3/interfaces/interface.rb +27 -26
  18. data/lib/openc3/interfaces/mqtt_interface.rb +240 -0
  19. data/lib/openc3/interfaces/protocols/override_protocol.rb +2 -61
  20. data/lib/openc3/interfaces/protocols/protocol.rb +6 -1
  21. data/lib/openc3/interfaces/simulated_target_interface.rb +1 -3
  22. data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -11
  23. data/lib/openc3/interfaces.rb +2 -3
  24. data/lib/openc3/logs/buffered_packet_log_reader.rb +2 -2
  25. data/lib/openc3/microservices/cleanup_microservice.rb +17 -1
  26. data/lib/openc3/microservices/decom_microservice.rb +12 -9
  27. data/lib/openc3/microservices/interface_microservice.rb +93 -9
  28. data/lib/openc3/microservices/log_microservice.rb +11 -5
  29. data/lib/openc3/microservices/microservice.rb +10 -9
  30. data/lib/openc3/microservices/periodic_microservice.rb +7 -0
  31. data/lib/openc3/microservices/reaction_microservice.rb +0 -33
  32. data/lib/openc3/microservices/reducer_microservice.rb +14 -10
  33. data/lib/openc3/microservices/text_log_microservice.rb +12 -3
  34. data/lib/openc3/microservices/timeline_microservice.rb +0 -6
  35. data/lib/openc3/microservices/trigger_group_microservice.rb +0 -20
  36. data/lib/openc3/models/cvt_model.rb +103 -47
  37. data/lib/openc3/models/interface_model.rb +23 -0
  38. data/lib/openc3/models/metric_model.rb +53 -6
  39. data/lib/openc3/models/microservice_model.rb +15 -1
  40. data/lib/openc3/models/model.rb +1 -1
  41. data/lib/openc3/models/plugin_model.rb +6 -1
  42. data/lib/openc3/models/secret_model.rb +53 -0
  43. data/lib/openc3/models/target_model.rb +2 -2
  44. data/lib/openc3/models/tool_model.rb +17 -8
  45. data/lib/openc3/operators/microservice_operator.rb +25 -0
  46. data/lib/openc3/operators/operator.rb +5 -1
  47. data/lib/openc3/packets/packet.rb +21 -7
  48. data/lib/openc3/packets/packet_item.rb +3 -2
  49. data/lib/openc3/script/api_shared.rb +18 -2
  50. data/lib/openc3/script/script.rb +8 -0
  51. data/lib/openc3/script/script_runner.rb +1 -2
  52. data/lib/openc3/script/storage.rb +2 -1
  53. data/lib/openc3/script/suite.rb +15 -11
  54. data/lib/openc3/system/system.rb +6 -3
  55. data/lib/openc3/topics/interface_topic.rb +17 -1
  56. data/lib/openc3/topics/router_topic.rb +17 -1
  57. data/lib/openc3/utilities/aws_bucket.rb +20 -3
  58. data/lib/openc3/utilities/bucket.rb +1 -1
  59. data/lib/openc3/utilities/bucket_file_cache.rb +1 -1
  60. data/lib/openc3/utilities/bucket_utilities.rb +1 -1
  61. data/lib/openc3/utilities/local_mode.rb +1 -0
  62. data/lib/openc3/utilities/metric.rb +77 -101
  63. data/lib/openc3/utilities/redis_secrets.rb +46 -0
  64. data/lib/openc3/utilities/s3_autoload.rb +19 -9
  65. data/lib/openc3/utilities/secrets.rb +63 -0
  66. data/lib/openc3/utilities/target_file.rb +3 -1
  67. data/lib/openc3/version.rb +5 -5
  68. data/templates/plugin-template/LICENSE.txt +7 -0
  69. data/templates/plugin-template/README.md +4 -3
  70. data/templates/plugin-template/plugin.gemspec +4 -4
  71. metadata +22 -3
  72. data/data/config/_interfaces.yaml.err +0 -1017
@@ -17,11 +17,12 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  module OpenC3
24
24
  autoload(:Interface, 'openc3/interfaces/interface.rb')
25
+ autoload(:MqttInterface, 'openc3/interfaces/mqtt_interface.rb')
25
26
  autoload(:StreamInterface, 'openc3/interfaces/stream_interface.rb')
26
27
  autoload(:SerialInterface, 'openc3/interfaces/serial_interface.rb')
27
28
  autoload(:SimulatedTargetInterface, 'openc3/interfaces/simulated_target_interface.rb')
@@ -31,7 +32,6 @@ module OpenC3
31
32
  autoload(:LincInterface, 'openc3/interfaces/linc_interface.rb')
32
33
  autoload(:LincHandshakeCommand, 'openc3/interfaces/linc_interface.rb')
33
34
  autoload(:LincHandshake, 'openc3/interfaces/linc_interface.rb')
34
- autoload(:DartStatusInterface, 'openc3/interfaces/dart_status_interface.rb')
35
35
 
36
36
  autoload(:Protocol, 'openc3/interfaces/protocols/protocol.rb')
37
37
  autoload(:BurstProtocol, 'openc3/interfaces/protocols/burst_protocol.rb')
@@ -41,7 +41,6 @@ module OpenC3
41
41
  autoload(:TemplateProtocol, 'openc3/interfaces/protocols/template_protocol.rb')
42
42
  autoload(:TerminatedProtocol, 'openc3/interfaces/protocols/terminated_protocol.rb')
43
43
 
44
- autoload(:OverrideProtocol, 'openc3/interfaces/protocols/override_protocol.rb')
45
44
  autoload(:CrcProtocol, 'openc3/interfaces/protocols/crc_protocol.rb')
46
45
  autoload(:IgnorePacketProtocol, 'openc3/interfaces/protocols/ignore_packet_protocol.rb')
47
46
  end
@@ -31,8 +31,8 @@ module OpenC3
31
31
  @buffer_depth = buffer_depth
32
32
  end
33
33
 
34
- def next_packet_time
35
- fill_buffer()
34
+ def next_packet_time(identify_and_define = true)
35
+ fill_buffer(identify_and_define)
36
36
  packet = @buffer[0]
37
37
  return packet.packet_time if packet
38
38
  return nil
@@ -27,6 +27,14 @@ require 'openc3/utilities/bucket_utilities'
27
27
 
28
28
  module OpenC3
29
29
  class CleanupMicroservice < Microservice
30
+ def initialize(*args)
31
+ super(*args)
32
+ @metric.set(name: 'cleanup_total', value: @count, type: 'counter')
33
+ @delete_count = 0
34
+ @metric.set(name: 'cleanup_delete_total', value: @delete_count, type: 'counter')
35
+ @sleeper = Sleeper.new
36
+ end
37
+
30
38
  def run
31
39
  split_name = @name.split("__")
32
40
  target_name = split_name[-1]
@@ -55,15 +63,23 @@ module OpenC3
55
63
  oldest_list.each_slice(1000) do |slice|
56
64
  bucket.delete_objects(bucket: ENV['OPENC3_LOGS_BUCKET'], keys: slice)
57
65
  @logger.info("Deleted #{slice.length} #{target_name} log files")
66
+ @delete_count += slice.length
67
+ @metric.set(name: 'cleanup_delete_total', value: @delete_count, type: 'counter')
58
68
  end
59
69
  end
60
70
  end
61
71
 
62
72
  @count += 1
73
+ @metric.set(name: 'cleanup_total', value: @count, type: 'counter')
63
74
  @state = 'SLEEPING'
64
- break if @microservice_sleeper.sleep(target.cleanup_poll_time)
75
+ break if @sleeper.sleep(target.cleanup_poll_time)
65
76
  end
66
77
  end
78
+
79
+ def shutdown
80
+ @sleeper.cancel
81
+ super()
82
+ end
67
83
  end
68
84
  end
69
85
 
@@ -28,15 +28,14 @@ require 'openc3/models/notification_model'
28
28
 
29
29
  module OpenC3
30
30
  class DecomMicroservice < Microservice
31
- DECOM_METRIC_NAME = "decom_packet_duration_seconds"
32
- LIMIT_METRIC_NAME = "limits_change_callback_duration_seconds"
33
- NS_PER_MSEC = 1000000
34
-
35
31
  def initialize(*args)
36
32
  super(*args)
37
33
  Topic.update_topic_offsets(@topics)
38
34
  System.telemetry.limits_change_callback = method(:limits_change_callback)
39
35
  LimitsEventTopic.sync_system(scope: @scope)
36
+ @error_count = 0
37
+ @metric.set(name: 'decom_total', value: @count, type: 'counter')
38
+ @metric.set(name: 'decom_error_total', value: @error_count, type: 'counter')
40
39
  end
41
40
 
42
41
  def run
@@ -50,18 +49,25 @@ module OpenC3
50
49
 
51
50
  decom_packet(topic, msg_id, msg_hash, redis)
52
51
  @count += 1
52
+ @metric.set(name: 'decom_total', value: @count, type: 'counter')
53
53
  end
54
54
  end
55
55
  LimitsEventTopic.sync_system_thread_body(scope: @scope)
56
56
  rescue => e
57
+ @error_count += 1
58
+ @metric.set(name: 'decom_error_total', value: @error_count, type: 'counter')
57
59
  @error = e
58
60
  @logger.error("Decom error: #{e.formatted}")
59
61
  end
60
62
  end
61
63
  end
62
64
 
63
- def decom_packet(topic, _msg_id, msg_hash, _redis)
65
+ def decom_packet(topic, msg_id, msg_hash, _redis)
64
66
  OpenC3.in_span("decom_packet") do
67
+ msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
68
+ delta = Time.now.to_f - msgid_seconds_from_epoch
69
+ @metric.set(name: 'decom_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and decom start')
70
+
65
71
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
66
72
  target_name = msg_hash["target_name"]
67
73
  packet_name = msg_hash["packet_name"]
@@ -75,8 +81,7 @@ module OpenC3
75
81
 
76
82
  TelemetryDecomTopic.write_packet(packet, scope: @scope)
77
83
  diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
78
- metric_labels = { "packet" => packet_name, "target" => target_name }
79
- @metric.add_sample(name: DECOM_METRIC_NAME, value: diff, labels: metric_labels)
84
+ @metric.set(name: 'decom_duration_seconds', value: diff, type: 'gauge', unit: 'seconds')
80
85
  end
81
86
  end
82
87
 
@@ -133,8 +138,6 @@ module OpenC3
133
138
  end
134
139
 
135
140
  diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
136
- labels = { "packet" => packet.packet_name, "target" => packet.target_name }
137
- @metric.add_sample(name: LIMIT_METRIC_NAME, value: diff, labels: labels)
138
141
  end
139
142
  end
140
143
  end
@@ -33,12 +33,17 @@ require 'openc3/topics/router_topic'
33
33
 
34
34
  module OpenC3
35
35
  class InterfaceCmdHandlerThread
36
- def initialize(interface, tlm, logger: nil, scope:)
36
+ def initialize(interface, tlm, logger: nil, metric: nil, scope:)
37
37
  @interface = interface
38
38
  @tlm = tlm
39
39
  @scope = scope
40
40
  @logger = logger
41
41
  @logger = Logger unless @logger
42
+ @metric = metric
43
+ @count = 0
44
+ @directive_count = 0
45
+ @metric.set(name: 'interface_directive_total', value: @directive_count, type: 'counter') if @metric
46
+ @metric.set(name: 'interface_cmd_total', value: @count, type: 'counter') if @metric
42
47
  end
43
48
 
44
49
  def start
@@ -59,10 +64,16 @@ module OpenC3
59
64
  end
60
65
 
61
66
  def run
62
- InterfaceTopic.receive_commands(@interface, scope: @scope) do |topic, msg_hash|
67
+ InterfaceTopic.receive_commands(@interface, scope: @scope) do |topic, msg_id, msg_hash, redis|
63
68
  OpenC3.with_context(msg_hash) do
69
+ msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
70
+ delta = Time.now.to_f - msgid_seconds_from_epoch
71
+ @metric.set(name: 'interface_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and interface cmd start') if @metric
72
+
64
73
  # Check for a raw write to the interface
65
74
  if topic =~ /CMD}INTERFACE/
75
+ @directive_count += 1
76
+ @metric.set(name: 'interface_directive_total', value: @directive_count, type: 'counter') if @metric
66
77
  if msg_hash['shutdown']
67
78
  @logger.info "#{@interface.name}: Shutdown requested"
68
79
  return
@@ -107,6 +118,28 @@ module OpenC3
107
118
  end
108
119
  next 'SUCCESS'
109
120
  end
121
+ if msg_hash.key?('interface_cmd')
122
+ params = JSON.parse(msg_hash['interface_cmd'], allow_nan: true, create_additions: true)
123
+ begin
124
+ @logger.info "#{@interface.name}: interface_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
125
+ @interface.interface_cmd(params['cmd_name'], params['cmd_params'])
126
+ rescue => e
127
+ @logger.error "#{@interface.name}: interface_cmd: #{e.formatted}"
128
+ next e.message
129
+ end
130
+ next 'SUCCESS'
131
+ end
132
+ if msg_hash.key?('protocol_cmd')
133
+ params = JSON.parse(msg_hash['protocol_cmd'], allow_nan: true, create_additions: true)
134
+ begin
135
+ @logger.info "#{@interface.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
136
+ @interface.protocol_cmd(params['cmd_name'], params['cmd_params'], read_write: params['read_write'], index: params['index'])
137
+ rescue => e
138
+ @logger.error "#{@interface.name}: protocol_cmd: #{e.formatted}"
139
+ next e.message
140
+ end
141
+ next 'SUCCESS'
142
+ end
110
143
  end
111
144
 
112
145
  target_name = msg_hash['target_name']
@@ -158,6 +191,9 @@ module OpenC3
158
191
 
159
192
  begin
160
193
  if @interface.connected?
194
+ @count += 1
195
+ @metric.set(name: 'interface_cmd_total', value: @count, type: 'counter') if @metric
196
+
161
197
  @interface.write(command)
162
198
  CommandTopic.write_packet(command, scope: @scope)
163
199
  CommandDecomTopic.write_packet(command, scope: @scope)
@@ -180,12 +216,17 @@ module OpenC3
180
216
  end
181
217
 
182
218
  class RouterTlmHandlerThread
183
- def initialize(router, tlm, logger: nil, scope:)
219
+ def initialize(router, tlm, logger: nil, metric: nil, scope:)
184
220
  @router = router
185
221
  @tlm = tlm
186
222
  @scope = scope
187
223
  @logger = logger
188
224
  @logger = Logger unless @logger
225
+ @metric = metric
226
+ @count = 0
227
+ @directive_count = 0
228
+ @metric.set(name: 'router_directive_total', value: @directive_count, type: 'counter') if @metric
229
+ @metric.set(name: 'router_tlm_total', value: @count, type: 'counter') if @metric
189
230
  end
190
231
 
191
232
  def start
@@ -206,9 +247,16 @@ module OpenC3
206
247
  end
207
248
 
208
249
  def run
209
- RouterTopic.receive_telemetry(@router, scope: @scope) do |topic, msg_hash|
250
+ RouterTopic.receive_telemetry(@router, scope: @scope) do |topic, msg_id, msg_hash, redis|
251
+ msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
252
+ delta = Time.now.to_f - msgid_seconds_from_epoch
253
+ @metric.set(name: 'router_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and router tlm start') if @metric
254
+
210
255
  # Check for commands to the router itself
211
256
  if /CMD}ROUTER/.match?(topic)
257
+ @directive_count += 1
258
+ @metric.set(name: 'router_directive_total', value: @directive_count, type: 'counter') if @metric
259
+
212
260
  if msg_hash['shutdown']
213
261
  @logger.info "#{@router.name}: Shutdown requested"
214
262
  return
@@ -234,10 +282,35 @@ module OpenC3
234
282
  @router.stop_raw_logging
235
283
  end
236
284
  end
285
+ if msg_hash.key?('router_cmd')
286
+ params = JSON.parse(msg_hash['router_cmd'], allow_nan: true, create_additions: true)
287
+ begin
288
+ @logger.info "#{@router.name}: router_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
289
+ @router.interface_cmd(params['cmd_name'], params['cmd_params'])
290
+ rescue => e
291
+ @logger.error "#{@router.name}: router_cmd: #{e.formatted}"
292
+ next e.message
293
+ end
294
+ next 'SUCCESS'
295
+ end
296
+ if msg_hash.key?('protocol_cmd')
297
+ params = JSON.parse(msg_hash['protocol_cmd'], allow_nan: true, create_additions: true)
298
+ begin
299
+ @logger.info "#{@router.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
300
+ @router.protocol_cmd(params['cmd_name'], params['cmd_params'], read_write: params['read_write'], index: params['index'])
301
+ rescue => e
302
+ @logger.error "#{@router.name}: protoco_cmd: #{e.formatted}"
303
+ next e.message
304
+ end
305
+ next 'SUCCESS'
306
+ end
237
307
  next 'SUCCESS'
238
308
  end
239
309
 
240
310
  if @router.connected?
311
+ @count += 1
312
+ @metric.set(name: 'router_tlm_total', value: @count, type: 'counter') if @metric
313
+
241
314
  target_name = msg_hash["target_name"]
242
315
  packet_name = msg_hash["packet_name"]
243
316
 
@@ -264,7 +337,14 @@ module OpenC3
264
337
  UNKNOWN_BYTES_TO_PRINT = 16
265
338
 
266
339
  def initialize(name)
340
+ @mutex = Mutex.new
267
341
  super(name)
342
+ if @interface_or_router == 'INTERFACE'
343
+ @metric.set(name: 'interface_tlm_total', value: @count, type: 'counter')
344
+ else
345
+ @metric.set(name: 'router_cmd_total', value: @count, type: 'counter')
346
+ end
347
+
268
348
  @interface_or_router = self.class.name.to_s.split("Microservice")[0].upcase.split("::")[-1]
269
349
  @scope = name.split("__")[0]
270
350
  interface_name = name.split("__")[2]
@@ -307,11 +387,10 @@ module OpenC3
307
387
  @cancel_thread = false
308
388
  @connection_failed_messages = []
309
389
  @connection_lost_messages = []
310
- @mutex = Mutex.new
311
390
  if @interface_or_router == 'INTERFACE'
312
- @handler_thread = InterfaceCmdHandlerThread.new(@interface, self, logger: @logger, scope: @scope)
391
+ @handler_thread = InterfaceCmdHandlerThread.new(@interface, self, logger: @logger, metric: @metric, scope: @scope)
313
392
  else
314
- @handler_thread = RouterTlmHandlerThread.new(@interface, self, logger: @logger, scope: @scope)
393
+ @handler_thread = RouterTlmHandlerThread.new(@interface, self, logger: @logger, metric: @metric, scope: @scope)
315
394
  end
316
395
  @handler_thread.start
317
396
  end
@@ -382,6 +461,11 @@ module OpenC3
382
461
  if packet
383
462
  handle_packet(packet)
384
463
  @count += 1
464
+ if @interface_or_router == 'INTERFACE'
465
+ @metric.set(name: 'interface_tlm_total', value: @count, type: 'counter')
466
+ else
467
+ @metric.set(name: 'router_cmd_total', value: @count, type: 'counter')
468
+ end
385
469
  else
386
470
  @logger.info "#{@interface.name}: Internal disconnect requested (returned nil)"
387
471
  handle_connection_lost()
@@ -560,7 +644,7 @@ module OpenC3
560
644
 
561
645
  # Disconnect from the interface and stop the thread
562
646
  def stop
563
- @logger.info "#{@interface.name}: stop requested"
647
+ @logger.info "#{@interface ? @interface.name : @name}: stop requested"
564
648
  @mutex.synchronize do
565
649
  # Need to make sure that @cancel_thread is set and the interface disconnected within
566
650
  # mutex to ensure that connect() is not called when we want to stop()
@@ -578,7 +662,7 @@ module OpenC3
578
662
  end
579
663
 
580
664
  def shutdown(sig = nil)
581
- @logger.info "#{@interface.name}: shutdown requested"
665
+ @logger.info "#{@interface ? @interface.name : @name}: shutdown requested"
582
666
  stop()
583
667
  super()
584
668
  end
@@ -55,6 +55,9 @@ module OpenC3
55
55
  @cycle_size = 50_000_000 unless @cycle_size # ~50 MB
56
56
 
57
57
  @buffer_depth = DEFAULT_BUFFER_DEPTH unless @buffer_depth
58
+ @error_count = 0
59
+ @metric.set(name: 'log_total', value: @count, type: 'counter')
60
+ @metric.set(name: 'log_error_total', value: @error_count, type: 'counter')
58
61
  end
59
62
 
60
63
  def run
@@ -65,6 +68,8 @@ module OpenC3
65
68
  Topic.read_topics(@topics) do |topic, msg_id, msg_hash, redis|
66
69
  break if @cancel_thread
67
70
  log_data(topic, msg_id, msg_hash, redis)
71
+ @count += 1
72
+ @metric.set(name: 'log_total', value: @count, type: 'counter')
68
73
  end
69
74
  end
70
75
  end
@@ -88,7 +93,10 @@ module OpenC3
88
93
  end
89
94
 
90
95
  def log_data(topic, msg_id, msg_hash, redis)
91
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
96
+ msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
97
+ delta = Time.now.to_f - msgid_seconds_from_epoch
98
+ @metric.set(name: 'log_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and log start')
99
+
92
100
  topic_split = topic.gsub(/{|}/, '').split("__") # Remove the redis hashtag curly braces
93
101
  target_name = topic_split[2]
94
102
  packet_name = topic_split[3]
@@ -103,13 +111,11 @@ module OpenC3
103
111
  data_key = "json_data"
104
112
  end
105
113
  @plws[target_name][rt_or_stored].buffered_write(packet_type, @cmd_or_tlm, target_name, packet_name, msg_hash["time"].to_i, rt_or_stored == :STORED, msg_hash[data_key], nil, topic, msg_id)
106
- @count += 1
107
- diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
108
- metric_labels = { "packet" => packet_name, "target" => target_name, "raw_or_decom" => @raw_or_decom.to_s, "cmd_or_tlm" => @cmd_or_tlm.to_s }
109
- @metric.add_sample(name: "log_duration_seconds", value: diff, labels: metric_labels)
110
114
  rescue => err
111
115
  @error = err
112
116
  @logger.error("#{@name} error: #{err.formatted}")
117
+ @error_count += 1
118
+ @metric.set(name: 'log_error_total', value: @error_count, type: 'counter')
113
119
  end
114
120
 
115
121
  def shutdown
@@ -27,6 +27,7 @@ OpenC3.require_file 'fileutils'
27
27
  OpenC3.require_file 'openc3/utilities/zip'
28
28
  OpenC3.require_file 'openc3/utilities/store'
29
29
  OpenC3.require_file 'openc3/utilities/bucket'
30
+ OpenC3.require_file 'openc3/utilities/secrets'
30
31
  OpenC3.require_file 'openc3/utilities/sleeper'
31
32
  OpenC3.require_file 'openc3/utilities/open_telemetry'
32
33
  OpenC3.require_file 'openc3/models/microservice_model'
@@ -43,6 +44,7 @@ module OpenC3
43
44
  attr_accessor :custom
44
45
  attr_accessor :scope
45
46
  attr_accessor :logger
47
+ attr_accessor :secrets
46
48
 
47
49
  def self.run(name = nil)
48
50
  name = ENV['OPENC3_MICROSERVICE_NAME'] unless name
@@ -93,6 +95,7 @@ module OpenC3
93
95
  @logger = Logger.new
94
96
  @logger.scope = @scope
95
97
  @logger.microservice_name = @name
98
+ @secrets = Secrets.getClient
96
99
 
97
100
  OpenC3.setup_open_telemetry(@name, false)
98
101
 
@@ -104,6 +107,9 @@ module OpenC3
104
107
  if @config
105
108
  @topics = @config['topics']
106
109
  @plugin = @config['plugin']
110
+ if @config['secrets']
111
+ @secrets.setup(@config['secrets'])
112
+ end
107
113
  else
108
114
  @config = {}
109
115
  @plugin = nil
@@ -125,7 +131,6 @@ module OpenC3
125
131
  @error = nil
126
132
  @custom = nil
127
133
  @state = 'INITIALIZED'
128
- metric_name = "metric_output_duration_seconds"
129
134
  @work_dir = @config["work_dir"]
130
135
 
131
136
  if is_plugin
@@ -174,16 +179,12 @@ module OpenC3
174
179
  end
175
180
  end
176
181
  else
177
- @microservice_sleeper = Sleeper.new
182
+ @microservice_status_sleeper = Sleeper.new
178
183
  @microservice_status_period_seconds = 5
179
184
  @microservice_status_thread = Thread.new do
180
185
  until @cancel_thread
181
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
182
- @metric.output
183
- diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
184
- @metric.add_sample(name: metric_name, value: diff, labels: {})
185
186
  MicroserviceStatusModel.set(as_json(:allow_nan => true), scope: @scope) unless @cancel_thread
186
- break if @microservice_sleeper.sleep(@microservice_status_period_seconds)
187
+ break if @microservice_status_sleeper.sleep(@microservice_status_period_seconds)
187
188
  end
188
189
  rescue Exception => err
189
190
  @logger.error "#{@name} status thread died: #{err.formatted}"
@@ -200,10 +201,10 @@ module OpenC3
200
201
  def shutdown
201
202
  @logger.info("Shutting down microservice: #{@name}")
202
203
  @cancel_thread = true
203
- @microservice_sleeper.cancel if @microservice_sleeper
204
+ @microservice_status_sleeper.cancel if @microservice_status_sleeper
204
205
  MicroserviceStatusModel.set(as_json(:allow_nan => true), scope: @scope)
205
206
  FileUtils.remove_entry(@temp_dir) if File.exist?(@temp_dir)
206
- @metric.destroy
207
+ @metric.shutdown
207
208
  @logger.info("Shutting down microservice complete: #{@name}")
208
209
  end
209
210
  end
@@ -24,6 +24,11 @@ module OpenC3
24
24
  STARTUP_DELAY_SECONDS = 2 * 60 # Two Minutes
25
25
  SLEEP_PERIOD_SECONDS = 24 * 60 * 60 # Run once per day
26
26
 
27
+ def initialize(*args)
28
+ super(*args)
29
+ @metric.set(name: 'periodic_total', value: @count, type: 'counter')
30
+ end
31
+
27
32
  def run
28
33
  @run_sleeper = Sleeper.new
29
34
  return if @run_sleeper.sleep(STARTUP_DELAY_SECONDS)
@@ -43,6 +48,8 @@ module OpenC3
43
48
  model.update
44
49
  end
45
50
  end
51
+ @count += 1
52
+ @metric.set(name: 'periodic_total', value: @count, type: 'counter')
46
53
  break if @cancel_thread
47
54
  break if @run_sleeper.sleep(SLEEP_PERIOD_SECONDS)
48
55
  end
@@ -222,8 +222,6 @@ module OpenC3
222
222
  # queues a trigger to evaluate against the reactions. The worker will check
223
223
  # the reactions to see if it needs to fire any reactions.
224
224
  class ReactionWorker
225
- REACTION_METRIC_NAME = 'reaction_duration_seconds'.freeze
226
-
227
225
  attr_reader :name, :scope, :share
228
226
 
229
227
  def initialize(name:, logger:, scope:, share:, ident:)
@@ -232,8 +230,6 @@ module OpenC3
232
230
  @scope = scope
233
231
  @share = share
234
232
  @ident = ident
235
- @metric_output_time = 0
236
- @metric = Metric.new(microservice: @name, scope: @scope)
237
233
  end
238
234
 
239
235
  def get_token(username)
@@ -269,10 +265,6 @@ module OpenC3
269
265
  process_enabled_trigger(data: data)
270
266
  end
271
267
  current_time = Time.now.to_i
272
- if @metric_output_time < current_time
273
- @metric.output
274
- @metric_output_time = current_time + 120
275
- end
276
268
  rescue StandardError => e
277
269
  @logger.error "ReactionWorker-#{@ident} failed to evaluate kind: #{kind} data: #{data}\n#{e.formatted}"
278
270
  end
@@ -281,24 +273,16 @@ module OpenC3
281
273
  end
282
274
 
283
275
  def process_enabled_trigger(data:)
284
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
285
276
  @share.reaction_base.get_reactions(trigger_name: data['name']).each do | reaction |
286
277
  run_reaction(reaction: reaction)
287
278
  end
288
- diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
289
- metric_labels = { 'type' => 'trigger', 'thread' => "worker-#{@ident}" }
290
- @metric.add_sample(name: REACTION_METRIC_NAME, value: diff, labels: metric_labels)
291
279
  end
292
280
 
293
281
  def run_reaction(reaction:)
294
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
295
282
  reaction.actions.each do |action|
296
283
  run_action(reaction: reaction, action: action)
297
284
  end
298
285
  @share.reaction_base.sleep(name: reaction.name)
299
- diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
300
- metric_labels = { 'type' => 'reaction', 'thread' => "worker-#{@ident}" }
301
- @metric.add_sample(name: REACTION_METRIC_NAME, value: diff, labels: metric_labels)
302
286
  end
303
287
 
304
288
  def run_action(reaction:, action:)
@@ -354,8 +338,6 @@ module OpenC3
354
338
  # The reaction snooze manager starts a thread pool and keeps track of when a
355
339
  # reaction is activated and to evalute triggers when the snooze is complete.
356
340
  class ReactionSnoozeManager
357
- SNOOZE_METRIC_NAME = 'snooze_manager_duration_seconds'.freeze
358
-
359
341
  attr_reader :name, :scope, :share, :thread_pool
360
342
 
361
343
  def initialize(name:, logger:, scope:, share:)
@@ -366,8 +348,6 @@ module OpenC3
366
348
  @worker_count = 3
367
349
  @thread_pool = nil
368
350
  @cancel_thread = false
369
- @metric = Metric.new(microservice: @name, scope: @scope)
370
- @metric_output_time = 0
371
351
  end
372
352
 
373
353
  def generate_thread_pool()
@@ -385,15 +365,7 @@ module OpenC3
385
365
  loop do
386
366
  begin
387
367
  current_time = Time.now.to_i
388
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
389
368
  manage_snoozed_reactions(current_time: current_time)
390
- diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
391
- metric_labels = { 'type' => 'snooze', 'thread' => "manager" }
392
- @metric.add_sample(name: SNOOZE_METRIC_NAME, value: diff, labels: metric_labels)
393
- if @metric_output_time < current_time
394
- @metric.output
395
- @metric_output_time = current_time + 120
396
- end
397
369
  rescue StandardError => e
398
370
  @logger.error "ReactionSnoozeManager failed to snooze reactions.\n#{e.formatted}"
399
371
  end
@@ -443,8 +415,6 @@ module OpenC3
443
415
  # reactions and triggers from redis. It then monitors the
444
416
  # AutonomicTopic for changes.
445
417
  class ReactionMicroservice < Microservice
446
- ACTION_METRIC_NAME = 'reactions_duration_seconds'.freeze
447
-
448
418
  attr_reader :name, :scope, :share, :manager, :manager_thread
449
419
 
450
420
  def initialize(*args)
@@ -459,11 +429,8 @@ module OpenC3
459
429
  @logger.info "ReactionMicroservice running"
460
430
  @manager_thread = Thread.new { @manager.run }
461
431
  loop do
462
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
463
432
  reactions = ReactionModel.all(scope: @scope)
464
433
  @share.reaction_base.setup(reactions: reactions)
465
- diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
466
- @metric.add_sample(name: ACTION_METRIC_NAME, value: diff, labels: { 'thread' => 'microservice' })
467
434
  break if @cancel_thread
468
435
 
469
436
  block_for_updates()
@@ -73,9 +73,9 @@ module OpenC3
73
73
  end
74
74
 
75
75
  class ReducerMicroservice < Microservice
76
- MINUTE_METRIC = 'reducer_minute_duration'
77
- HOUR_METRIC = 'reducer_hour_duration'
78
- DAY_METRIC = 'reducer_day_duration'
76
+ MINUTE_METRIC = 'reducer_minute_processing_seconds'
77
+ HOUR_METRIC = 'reducer_hour_processing_seconds'
78
+ DAY_METRIC = 'reducer_day_processing_seconds'
79
79
 
80
80
  # How long to wait for any currently running jobs to complete before killing them
81
81
  SHUTDOWN_DELAY_SECS = 5
@@ -105,6 +105,10 @@ module OpenC3
105
105
  @buffer_depth = 10 unless @buffer_depth
106
106
  @target_name = name.split('__')[-1]
107
107
  @packet_logs = {}
108
+
109
+ @error_count = 0
110
+ @metric.set(name: 'reducer_total', value: @count, type: 'counter')
111
+ @metric.set(name: 'reducer_error_total', value: @error_count, type: 'counter')
108
112
  end
109
113
 
110
114
  def run
@@ -148,13 +152,7 @@ module OpenC3
148
152
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
149
153
  yield
150
154
  elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
151
- @metric.add_sample(
152
- name: name,
153
- value: elapsed,
154
- labels: {
155
- 'target' => @target_name,
156
- },
157
- )
155
+ @metric.set(name: name, value: elapsed, type: 'gauge', unit: 'seconds')
158
156
  end
159
157
 
160
158
  def reduce_minute
@@ -366,6 +364,10 @@ module OpenC3
366
364
  file.delete # Remove the local copy
367
365
 
368
366
  write_all_entries(reducer_state, plw, type, target_name, stored)
367
+
368
+ @count += 1
369
+ @metric.set(name: 'reducer_total', value: @count, type: 'counter')
370
+
369
371
  true
370
372
  rescue => e
371
373
  if file.local_path and File.exist?(file.local_path)
@@ -373,6 +375,8 @@ module OpenC3
373
375
  else
374
376
  @logger.error("Reducer Error: #{filename}: \n#{e.formatted}")
375
377
  end
378
+ @error_count += 1
379
+ @metric.set(name: 'reducer_error_total', value: @error_count, type: 'counter')
376
380
  false
377
381
  end
378
382