openc3 5.0.11 → 5.1.1
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.
- checksums.yaml +4 -4
- data/Guardfile +3 -0
- data/LICENSE.txt +7 -5
- data/README.md +11 -9
- data/Rakefile +3 -0
- data/bin/cstol_converter +3 -0
- data/bin/openc3cli +29 -18
- data/bin/rubysloc +3 -0
- data/data/config/screen.yaml +10 -2
- data/data/config/target.yaml +1 -1
- data/data/config/widgets.yaml +6 -6
- data/ext/mkrf_conf.rb +3 -0
- data/ext/openc3/ext/array/array.c +3 -0
- data/ext/openc3/ext/buffered_file/buffered_file.c +3 -0
- data/ext/openc3/ext/config_parser/config_parser.c +3 -0
- data/ext/openc3/ext/crc/crc.c +3 -0
- data/ext/openc3/ext/openc3_io/openc3_io.c +3 -0
- data/ext/openc3/ext/packet/packet.c +3 -0
- data/ext/openc3/ext/platform/platform.c +3 -0
- data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +3 -0
- data/ext/openc3/ext/string/string.c +3 -0
- data/ext/openc3/ext/structure/structure.c +3 -0
- data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +3 -0
- data/ext/openc3/ext/telemetry/telemetry.c +3 -0
- data/lib/cosmos.rb +3 -0
- data/lib/cosmosc2.rb +3 -0
- data/lib/openc3/accessors/accessor.rb +3 -0
- data/lib/openc3/accessors/binary_accessor.rb +3 -0
- data/lib/openc3/accessors/cbor_accessor.rb +3 -0
- data/lib/openc3/accessors/html_accessor.rb +3 -0
- data/lib/openc3/accessors/json_accessor.rb +4 -1
- data/lib/openc3/accessors/xml_accessor.rb +3 -0
- data/lib/openc3/accessors.rb +3 -0
- data/lib/openc3/api/api.rb +3 -0
- data/lib/openc3/api/authorized_api.rb +3 -0
- data/lib/openc3/api/cmd_api.rb +6 -3
- data/lib/openc3/api/config_api.rb +3 -0
- data/lib/openc3/api/interface_api.rb +6 -2
- data/lib/openc3/api/limits_api.rb +54 -61
- data/lib/openc3/api/router_api.rb +6 -3
- data/lib/openc3/api/settings_api.rb +3 -0
- data/lib/openc3/api/target_api.rb +3 -0
- data/lib/openc3/api/tlm_api.rb +27 -32
- data/lib/openc3/bridge/bridge.rb +3 -0
- data/lib/openc3/bridge/bridge_config.rb +3 -0
- data/lib/openc3/bridge/bridge_interface_thread.rb +3 -0
- data/lib/openc3/bridge/bridge_router_thread.rb +3 -0
- data/lib/openc3/ccsds/ccsds_packet.rb +3 -0
- data/lib/openc3/ccsds/ccsds_parser.rb +3 -0
- data/lib/openc3/config/config_parser.rb +3 -0
- data/lib/openc3/config/meta_config_parser.rb +3 -0
- data/lib/openc3/conversions/conversion.rb +3 -0
- data/lib/openc3/conversions/generic_conversion.rb +3 -0
- data/lib/openc3/conversions/packet_time_formatted_conversion.rb +3 -0
- data/lib/openc3/conversions/packet_time_seconds_conversion.rb +3 -0
- data/lib/openc3/conversions/polynomial_conversion.rb +3 -0
- data/lib/openc3/conversions/processor_conversion.rb +3 -0
- data/lib/openc3/conversions/received_count_conversion.rb +3 -0
- data/lib/openc3/conversions/received_time_formatted_conversion.rb +3 -0
- data/lib/openc3/conversions/received_time_seconds_conversion.rb +3 -0
- data/lib/openc3/conversions/segmented_polynomial_conversion.rb +3 -0
- data/lib/openc3/conversions/unix_time_conversion.rb +3 -0
- data/lib/openc3/conversions/unix_time_formatted_conversion.rb +3 -0
- data/lib/openc3/conversions/unix_time_seconds_conversion.rb +3 -0
- data/lib/openc3/conversions.rb +3 -0
- data/lib/openc3/core_ext/array.rb +3 -0
- data/lib/openc3/core_ext/binding.rb +3 -0
- data/lib/openc3/core_ext/class.rb +3 -0
- data/lib/openc3/core_ext/exception.rb +3 -0
- data/lib/openc3/core_ext/file.rb +3 -0
- data/lib/openc3/core_ext/hash.rb +3 -0
- data/lib/openc3/core_ext/io.rb +3 -0
- data/lib/openc3/core_ext/kernel.rb +3 -0
- data/lib/openc3/core_ext/math.rb +3 -0
- data/lib/openc3/core_ext/matrix.rb +3 -0
- data/lib/openc3/core_ext/objectspace.rb +3 -0
- data/lib/openc3/core_ext/openc3_io.rb +3 -0
- data/lib/openc3/core_ext/range.rb +3 -0
- data/lib/openc3/core_ext/socket.rb +3 -0
- data/lib/openc3/core_ext/string.rb +3 -0
- data/lib/openc3/core_ext/stringio.rb +3 -0
- data/lib/openc3/core_ext/tempfile.rb +3 -0
- data/lib/openc3/core_ext/time.rb +3 -0
- data/lib/openc3/core_ext.rb +3 -0
- data/lib/openc3/interfaces/interface.rb +3 -0
- data/lib/openc3/interfaces/linc_interface.rb +3 -0
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +3 -0
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +3 -0
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +3 -0
- data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +3 -0
- data/lib/openc3/interfaces/protocols/length_protocol.rb +3 -0
- data/lib/openc3/interfaces/protocols/override_protocol.rb +3 -0
- data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +3 -0
- data/lib/openc3/interfaces/protocols/protocol.rb +3 -0
- data/lib/openc3/interfaces/protocols/template_protocol.rb +3 -0
- data/lib/openc3/interfaces/protocols/terminated_protocol.rb +3 -0
- data/lib/openc3/interfaces/serial_interface.rb +3 -0
- data/lib/openc3/interfaces/simulated_target_interface.rb +3 -0
- data/lib/openc3/interfaces/stream_interface.rb +3 -0
- data/lib/openc3/interfaces/tcpip_client_interface.rb +3 -0
- data/lib/openc3/interfaces/tcpip_server_interface.rb +3 -0
- data/lib/openc3/interfaces/udp_interface.rb +3 -0
- data/lib/openc3/interfaces.rb +3 -0
- data/lib/openc3/io/buffered_file.rb +3 -0
- data/lib/openc3/io/io_multiplexer.rb +8 -0
- data/lib/openc3/io/json_api_object.rb +5 -2
- data/lib/openc3/io/json_drb.rb +3 -0
- data/lib/openc3/io/json_drb_object.rb +5 -2
- data/lib/openc3/io/json_drb_rack.rb +3 -0
- data/lib/openc3/io/json_rpc.rb +8 -3
- data/lib/openc3/io/openc3_snmp.rb +3 -0
- data/lib/openc3/io/posix_serial_driver.rb +3 -0
- data/lib/openc3/io/raw_logger.rb +3 -0
- data/lib/openc3/io/raw_logger_pair.rb +3 -0
- data/lib/openc3/io/serial_driver.rb +3 -0
- data/lib/openc3/io/stderr.rb +3 -0
- data/lib/openc3/io/stdout.rb +3 -0
- data/lib/openc3/io/udp_sockets.rb +3 -0
- data/lib/openc3/io/win32_serial_driver.rb +3 -0
- data/lib/openc3/logs/buffered_packet_log_reader.rb +65 -0
- data/lib/openc3/logs/buffered_packet_log_writer.rb +120 -0
- data/lib/openc3/logs/log_writer.rb +95 -40
- data/lib/openc3/logs/packet_log_constants.rb +9 -0
- data/lib/openc3/logs/packet_log_reader.rb +34 -3
- data/lib/openc3/logs/packet_log_writer.rb +85 -18
- data/lib/openc3/logs/text_log_writer.rb +9 -5
- data/lib/openc3/logs.rb +8 -2
- data/lib/openc3/microservices/cleanup_microservice.rb +18 -18
- data/lib/openc3/microservices/decom_microservice.rb +30 -24
- data/lib/openc3/microservices/interface_microservice.rb +136 -91
- data/lib/openc3/microservices/log_microservice.rb +35 -13
- data/lib/openc3/microservices/microservice.rb +16 -14
- data/lib/openc3/microservices/plugin_microservice.rb +3 -1
- data/lib/openc3/microservices/reaction_microservice.rb +4 -1
- data/lib/openc3/microservices/reducer_microservice.rb +332 -149
- data/lib/openc3/microservices/router_microservice.rb +3 -0
- data/lib/openc3/microservices/text_log_microservice.rb +22 -7
- data/lib/openc3/microservices/timeline_microservice.rb +4 -1
- data/lib/openc3/microservices/trigger_group_microservice.rb +3 -0
- data/lib/openc3/models/activity_model.rb +3 -0
- data/lib/openc3/models/auth_model.rb +3 -0
- data/lib/openc3/models/cvt_model.rb +14 -5
- data/lib/openc3/models/environment_model.rb +3 -0
- data/lib/openc3/models/gem_model.rb +30 -51
- data/lib/openc3/models/info_model.rb +3 -0
- data/lib/openc3/models/interface_model.rb +3 -0
- data/lib/openc3/models/interface_status_model.rb +4 -1
- data/lib/openc3/models/metadata_model.rb +3 -0
- data/lib/openc3/models/metric_model.rb +3 -0
- data/lib/openc3/models/microservice_model.rb +9 -6
- data/lib/openc3/models/microservice_status_model.rb +4 -1
- data/lib/openc3/models/model.rb +3 -0
- data/lib/openc3/models/note_model.rb +3 -0
- data/lib/openc3/models/notification_model.rb +3 -0
- data/lib/openc3/models/ping_model.rb +3 -0
- data/lib/openc3/models/plugin_model.rb +20 -14
- data/lib/openc3/models/process_status_model.rb +4 -1
- data/lib/openc3/models/reaction_model.rb +3 -0
- data/lib/openc3/models/reducer_model.rb +31 -24
- data/lib/openc3/models/router_model.rb +3 -0
- data/lib/openc3/models/router_status_model.rb +3 -0
- data/lib/openc3/models/scope_model.rb +3 -4
- data/lib/openc3/models/settings_model.rb +3 -0
- data/lib/openc3/models/sorted_model.rb +3 -0
- data/lib/openc3/models/target_model.rb +61 -94
- data/lib/openc3/models/timeline_model.rb +4 -1
- data/lib/openc3/models/tool_config_model.rb +3 -0
- data/lib/openc3/models/tool_model.rb +11 -9
- data/lib/openc3/models/trigger_group_model.rb +3 -0
- data/lib/openc3/models/trigger_model.rb +3 -0
- data/lib/openc3/models/widget_model.rb +18 -11
- data/lib/openc3/operators/microservice_operator.rb +3 -0
- data/lib/openc3/operators/operator.rb +105 -34
- data/lib/openc3/packets/commands.rb +3 -0
- data/lib/openc3/packets/json_packet.rb +87 -14
- data/lib/openc3/packets/limits.rb +4 -1
- data/lib/openc3/packets/limits_response.rb +3 -0
- data/lib/openc3/packets/packet.rb +5 -1
- data/lib/openc3/packets/packet_config.rb +3 -0
- data/lib/openc3/packets/packet_item.rb +9 -3
- data/lib/openc3/packets/packet_item_limits.rb +3 -0
- data/lib/openc3/packets/parsers/format_string_parser.rb +3 -0
- data/lib/openc3/packets/parsers/limits_parser.rb +3 -0
- data/lib/openc3/packets/parsers/limits_response_parser.rb +3 -0
- data/lib/openc3/packets/parsers/packet_item_parser.rb +3 -0
- data/lib/openc3/packets/parsers/packet_parser.rb +3 -0
- data/lib/openc3/packets/parsers/processor_parser.rb +3 -0
- data/lib/openc3/packets/parsers/state_parser.rb +3 -0
- data/lib/openc3/packets/parsers/xtce_converter.rb +3 -0
- data/lib/openc3/packets/parsers/xtce_parser.rb +3 -0
- data/lib/openc3/packets/structure.rb +3 -0
- data/lib/openc3/packets/structure_item.rb +3 -0
- data/lib/openc3/packets/telemetry.rb +3 -0
- data/lib/openc3/processors/processor.rb +3 -0
- data/lib/openc3/processors/statistics_processor.rb +3 -0
- data/lib/openc3/processors/watermark_processor.rb +3 -0
- data/lib/openc3/processors.rb +3 -0
- data/lib/openc3/script/api_shared.rb +35 -6
- data/lib/openc3/script/calendar.rb +3 -0
- data/lib/openc3/script/commands.rb +3 -0
- data/lib/openc3/script/exceptions.rb +3 -0
- data/lib/openc3/script/extract.rb +3 -0
- data/lib/openc3/script/limits.rb +3 -24
- data/lib/openc3/script/script.rb +11 -7
- data/lib/openc3/script/script_runner.rb +3 -0
- data/lib/openc3/script/storage.rb +33 -16
- data/lib/openc3/script/suite.rb +3 -0
- data/lib/openc3/script/suite_results.rb +3 -0
- data/lib/openc3/script/suite_runner.rb +3 -0
- data/lib/openc3/script/telemetry.rb +43 -0
- data/lib/openc3/script.rb +3 -0
- data/lib/openc3/streams/serial_stream.rb +3 -0
- data/lib/openc3/streams/stream.rb +3 -0
- data/lib/openc3/streams/tcpip_client_stream.rb +3 -0
- data/lib/openc3/streams/tcpip_socket_stream.rb +3 -0
- data/lib/openc3/system/system.rb +23 -10
- data/lib/openc3/system/system_config.rb +3 -0
- data/lib/openc3/system/target.rb +3 -0
- data/lib/openc3/system.rb +3 -0
- data/lib/openc3/tools/cmd_tlm_server/api.rb +3 -0
- data/lib/openc3/tools/cmd_tlm_server/cmd_tlm_server_config.rb +3 -0
- data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +3 -0
- data/lib/openc3/tools/table_manager/table.rb +3 -0
- data/lib/openc3/tools/table_manager/table_config.rb +3 -0
- data/lib/openc3/tools/table_manager/table_item.rb +3 -0
- data/lib/openc3/tools/table_manager/table_item_parser.rb +3 -0
- data/lib/openc3/tools/table_manager/table_manager_core.rb +3 -0
- data/lib/openc3/tools/table_manager/table_parser.rb +3 -0
- data/lib/openc3/tools/test_runner/test.rb +3 -0
- data/lib/openc3/top_level.rb +3 -0
- data/lib/openc3/topics/autonomic_topic.rb +3 -0
- data/lib/openc3/topics/calendar_topic.rb +3 -0
- data/lib/openc3/topics/command_decom_topic.rb +4 -1
- data/lib/openc3/topics/command_topic.rb +6 -1
- data/lib/openc3/topics/config_topic.rb +3 -0
- data/lib/openc3/topics/interface_topic.rb +9 -2
- data/lib/openc3/topics/limits_event_topic.rb +144 -10
- data/lib/openc3/topics/notifications_topic.rb +3 -0
- data/lib/openc3/topics/router_topic.rb +10 -3
- data/lib/openc3/topics/telemetry_decom_topic.rb +26 -20
- data/lib/openc3/topics/telemetry_reduced_topics.rb +92 -0
- data/lib/openc3/topics/telemetry_topic.rb +5 -2
- data/lib/openc3/topics/timeline_topic.rb +3 -0
- data/lib/openc3/topics/topic.rb +3 -0
- data/lib/openc3/utilities/authentication.rb +3 -0
- data/lib/openc3/utilities/authorization.rb +3 -0
- data/lib/openc3/utilities/aws_bucket.rb +199 -0
- data/lib/openc3/utilities/bucket.rb +82 -0
- data/lib/openc3/utilities/bucket_file_cache.rb +264 -0
- data/lib/openc3/utilities/bucket_utilities.rb +109 -0
- data/lib/openc3/utilities/crc.rb +3 -0
- data/lib/openc3/utilities/csv.rb +3 -0
- data/lib/openc3/utilities/local_bucket.rb +28 -0
- data/lib/openc3/utilities/local_mode.rb +47 -61
- data/lib/openc3/utilities/logger.rb +7 -1
- data/lib/openc3/utilities/message_log.rb +7 -4
- data/lib/openc3/utilities/metric.rb +4 -1
- data/lib/openc3/utilities/open_telemetry.rb +96 -0
- data/lib/openc3/utilities/process_manager.rb +3 -0
- data/lib/openc3/utilities/quaternion.rb +3 -0
- data/lib/openc3/utilities/ruby_lex_utils.rb +3 -0
- data/lib/openc3/utilities/s3_autoload.rb +3 -3
- data/lib/openc3/utilities/simulated_target.rb +3 -0
- data/lib/openc3/utilities/sleeper.rb +3 -0
- data/lib/openc3/utilities/store.rb +3 -0
- data/lib/openc3/utilities/store_autoload.rb +30 -23
- data/lib/openc3/utilities/target_file.rb +70 -83
- data/lib/openc3/utilities/zip.rb +3 -0
- data/lib/openc3/utilities.rb +3 -0
- data/lib/openc3/version.rb +6 -6
- data/lib/openc3/win32/excel.rb +3 -0
- data/lib/openc3/win32/win32.rb +3 -0
- data/lib/openc3/win32/win32_main.rb +3 -0
- data/lib/openc3.rb +3 -0
- data/tasks/gemfile_stats.rake +3 -0
- data/tasks/spec.rake +3 -0
- data/templates/plugin-template/plugin.gemspec +1 -1
- metadata +112 -6
- data/lib/openc3/utilities/s3.rb +0 -220
- data/lib/openc3/utilities/s3_file_cache.rb +0 -274
@@ -16,15 +16,62 @@
|
|
16
16
|
# Modified by OpenC3, Inc.
|
17
17
|
# All changes Copyright 2022, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
|
+
#
|
20
|
+
# This file may also be used under the terms of a commercial license
|
21
|
+
# if purchased from OpenC3, Inc.
|
19
22
|
|
20
23
|
require 'openc3/microservices/microservice'
|
21
24
|
require 'openc3/topics/topic'
|
25
|
+
require 'openc3/topics/telemetry_reduced_topics'
|
22
26
|
require 'openc3/packets/json_packet'
|
23
|
-
require 'openc3/utilities/
|
27
|
+
require 'openc3/utilities/bucket_file_cache'
|
24
28
|
require 'openc3/models/reducer_model'
|
29
|
+
require 'openc3/logs/buffered_packet_log_writer'
|
25
30
|
require 'rufus-scheduler'
|
26
31
|
|
27
32
|
module OpenC3
|
33
|
+
class ReducerState
|
34
|
+
attr_accessor :reduced
|
35
|
+
attr_accessor :raw_keys
|
36
|
+
attr_accessor :converted_keys
|
37
|
+
attr_accessor :entry_time
|
38
|
+
attr_accessor :entry_samples
|
39
|
+
attr_accessor :current_time
|
40
|
+
attr_accessor :previous_time
|
41
|
+
attr_accessor :raw_values
|
42
|
+
attr_accessor :raw_max_values
|
43
|
+
attr_accessor :raw_min_values
|
44
|
+
attr_accessor :raw_avg_values
|
45
|
+
attr_accessor :raw_stddev_values
|
46
|
+
attr_accessor :converted_values
|
47
|
+
attr_accessor :converted_max_values
|
48
|
+
attr_accessor :converted_min_values
|
49
|
+
attr_accessor :converted_avg_values
|
50
|
+
attr_accessor :converted_stddev_values
|
51
|
+
attr_accessor :first
|
52
|
+
|
53
|
+
def initialize
|
54
|
+
@reduced = {}
|
55
|
+
@raw_keys = nil
|
56
|
+
@converted_keys = nil
|
57
|
+
@entry_time = nil
|
58
|
+
@entry_samples = nil
|
59
|
+
@current_time = nil
|
60
|
+
@previous_time = nil
|
61
|
+
@raw_values = nil
|
62
|
+
@raw_max_values = nil
|
63
|
+
@raw_min_values = nil
|
64
|
+
@raw_avg_values = nil
|
65
|
+
@raw_stddev_values = nil
|
66
|
+
@converted_values = nil
|
67
|
+
@converted_max_values = nil
|
68
|
+
@converted_min_values = nil
|
69
|
+
@converted_avg_values = nil
|
70
|
+
@converted_stddev_values = nil
|
71
|
+
@first = true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
28
75
|
class ReducerMicroservice < Microservice
|
29
76
|
MINUTE_METRIC = 'reducer_minute_duration'
|
30
77
|
HOUR_METRIC = 'reducer_hour_duration'
|
@@ -32,17 +79,30 @@ module OpenC3
|
|
32
79
|
|
33
80
|
# How long to wait for any currently running jobs to complete before killing them
|
34
81
|
SHUTDOWN_DELAY_SECS = 5
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
82
|
+
MINUTE_ENTRY_NSECS = 60 * 1_000_000_000
|
83
|
+
MINUTE_FILE_NSECS = 3600 * 1_000_000_000
|
84
|
+
HOUR_ENTRY_NSECS = 3600 * 1_000_000_000
|
85
|
+
HOUR_FILE_NSECS = 3600 * 24 * 1_000_000_000
|
86
|
+
DAY_ENTRY_NSECS = 3600 * 24 * 1_000_000_000
|
87
|
+
DAY_FILE_NSECS = 3600 * 24 * 5 * 1_000_000_000
|
41
88
|
|
42
89
|
# @param name [String] Microservice name formatted as <SCOPE>__REDUCER__<TARGET>
|
43
90
|
# where <SCOPE> and <TARGET> are variables representing the scope name and target name
|
44
91
|
def initialize(name)
|
45
92
|
super(name, is_plugin: false)
|
93
|
+
|
94
|
+
if @config['options']
|
95
|
+
@config['options'].each do |option|
|
96
|
+
case option[0].upcase
|
97
|
+
when 'BUFFER_DEPTH' # Buffer depth to write in time order
|
98
|
+
@buffer_depth = option[1].to_i
|
99
|
+
else
|
100
|
+
Logger.error("Unknown option passed to microservice #{@name}: #{option}")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@buffer_depth = 10 unless @buffer_depth
|
46
106
|
@target_name = name.split('__')[-1]
|
47
107
|
@packet_logs = {}
|
48
108
|
end
|
@@ -69,11 +129,17 @@ module OpenC3
|
|
69
129
|
end
|
70
130
|
|
71
131
|
def shutdown
|
132
|
+
Logger.info("Shutting down reducer microservice: #{@name}")
|
72
133
|
@scheduler.shutdown(wait: SHUTDOWN_DELAY_SECS) if @scheduler
|
73
134
|
|
74
135
|
# Make sure all the existing logs are properly closed down
|
136
|
+
threads = []
|
75
137
|
@packet_logs.each do |name, log|
|
76
|
-
log.shutdown
|
138
|
+
threads.concat(log.shutdown)
|
139
|
+
end
|
140
|
+
# Wait for all the logging threads to move files to buckets
|
141
|
+
threads.flatten.compact.each do |thread|
|
142
|
+
thread.join
|
77
143
|
end
|
78
144
|
super()
|
79
145
|
end
|
@@ -96,7 +162,7 @@ module OpenC3
|
|
96
162
|
ReducerModel
|
97
163
|
.all_files(type: :DECOM, target: @target_name, scope: @scope)
|
98
164
|
.each do |file|
|
99
|
-
process_file(file, 'minute',
|
165
|
+
process_file(file, 'minute', MINUTE_ENTRY_NSECS, MINUTE_FILE_NSECS)
|
100
166
|
ReducerModel.rm_file(file)
|
101
167
|
end
|
102
168
|
end
|
@@ -107,7 +173,7 @@ module OpenC3
|
|
107
173
|
ReducerModel
|
108
174
|
.all_files(type: :MINUTE, target: @target_name, scope: @scope)
|
109
175
|
.each do |file|
|
110
|
-
process_file(file, 'hour',
|
176
|
+
process_file(file, 'hour', HOUR_ENTRY_NSECS, HOUR_FILE_NSECS)
|
111
177
|
ReducerModel.rm_file(file)
|
112
178
|
end
|
113
179
|
end
|
@@ -118,195 +184,312 @@ module OpenC3
|
|
118
184
|
ReducerModel
|
119
185
|
.all_files(type: :HOUR, target: @target_name, scope: @scope)
|
120
186
|
.each do |file|
|
121
|
-
process_file(file, 'day',
|
187
|
+
process_file(file, 'day', DAY_ENTRY_NSECS, DAY_FILE_NSECS)
|
122
188
|
ReducerModel.rm_file(file)
|
123
189
|
end
|
124
190
|
end
|
125
191
|
end
|
126
192
|
|
127
|
-
def process_file(filename, type,
|
128
|
-
file =
|
193
|
+
def process_file(filename, type, entry_nanoseconds, file_nanoseconds)
|
194
|
+
file = BucketFile.new(filename)
|
129
195
|
file.retrieve
|
130
196
|
|
131
197
|
# Determine if we already have a PacketLogWriter created
|
132
|
-
|
133
|
-
|
198
|
+
_, _, scope, target_name, _, rt_or_stored, _ = File.basename(filename).split('__')
|
199
|
+
stored = (rt_or_stored == "stored")
|
200
|
+
|
134
201
|
if @target_name != target_name
|
135
202
|
raise "Target name in file #{filename} does not match microservice target name #{@target_name}"
|
136
203
|
end
|
137
|
-
plw = @packet_logs["#{scope}__#{target_name}__#{
|
204
|
+
plw = @packet_logs["#{scope}__#{target_name}__#{rt_or_stored}__#{type}"]
|
138
205
|
unless plw
|
139
206
|
# Create a new PacketLogWriter for this reduced data
|
140
|
-
# e.g. DEFAULT/reduced_minute_logs/tlm/INST/
|
141
|
-
#
|
142
|
-
remote_log_directory = "#{scope}/reduced_#{type}_logs/tlm/#{target_name}
|
143
|
-
|
144
|
-
plw =
|
145
|
-
@packet_logs["#{scope}__#{target_name}__#{
|
207
|
+
# e.g. DEFAULT/reduced_minute_logs/tlm/INST/20220101/
|
208
|
+
# 20220101204857274290500__20220101205857276524900__DEFAULT__INST__ALL__rt__reduced_minute.bin
|
209
|
+
remote_log_directory = "#{scope}/reduced_#{type}_logs/tlm/#{target_name}"
|
210
|
+
label = "#{scope}__#{target_name}__ALL__#{rt_or_stored}__reduced_#{type}"
|
211
|
+
plw = BufferedPacketLogWriter.new(remote_log_directory, label, true, nil, 1_000_000_000, nil, nil, true, @buffer_depth)
|
212
|
+
@packet_logs["#{scope}__#{target_name}__#{rt_or_stored}__#{type}"] = plw
|
146
213
|
end
|
147
214
|
|
148
|
-
|
149
|
-
|
150
|
-
entry_time = nil
|
151
|
-
current_time = nil
|
152
|
-
previous_time = nil
|
215
|
+
# The lifetime of all these variables is a single file - single target / multiple packets
|
216
|
+
reducer_state = {}
|
153
217
|
plr = OpenC3::PacketLogReader.new
|
154
218
|
plr.each(file.local_path) do |packet|
|
155
|
-
#
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
data.merge!(converted_data)
|
160
|
-
|
161
|
-
previous_time = current_time
|
162
|
-
current_time = packet.packet_time.to_f
|
163
|
-
entry_time ||= current_time
|
164
|
-
data_keys ||= data.keys
|
219
|
+
# Check to see if we should start a new log file before processing this packet
|
220
|
+
current_time = packet.packet_time.to_nsec_from_epoch
|
221
|
+
check_new_file(reducer_state, plw, type, target_name, stored, current_time, file_nanoseconds)
|
222
|
+
state = setup_state(reducer_state, packet, current_time)
|
165
223
|
|
166
224
|
# Determine if we've rolled over a entry boundary
|
167
|
-
# We have to use current %
|
168
|
-
# we don't know the data rates. We also have to check for current - previous >=
|
225
|
+
# We have to use current % entry_nanoseconds < previous % entry_nanoseconds because
|
226
|
+
# we don't know the data rates. We also have to check for current - previous >= entry_nanoseconds
|
169
227
|
# in case the data rate is so slow we don't have multiple samples per entry
|
170
|
-
if previous_time &&
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
)
|
175
|
-
Logger.debug("Reducer: Roll over entry boundary cur_time:#{current_time}")
|
176
|
-
|
177
|
-
reduce(type, data_keys, reduced)
|
178
|
-
plw.write(
|
179
|
-
:JSON_PACKET,
|
180
|
-
:TLM,
|
181
|
-
target_name,
|
182
|
-
packet_name,
|
183
|
-
entry_time * Time::NSEC_PER_SECOND,
|
184
|
-
false,
|
185
|
-
JSON.generate(reduced.as_json(:allow_nan => true)),
|
228
|
+
if state.previous_time &&
|
229
|
+
(
|
230
|
+
(state.current_time % entry_nanoseconds < state.previous_time % entry_nanoseconds) || # Try to create at perfect intervals
|
231
|
+
(state.current_time - state.previous_time >= entry_nanoseconds) # Handle big gaps
|
186
232
|
)
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
233
|
+
write_entry(state, plw, type, target_name, packet.packet_name, stored)
|
234
|
+
if check_new_file(reducer_state, plw, type, target_name, stored, current_time, file_nanoseconds)
|
235
|
+
state = setup_state(reducer_state, packet, current_time)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
if type == 'minute'
|
240
|
+
state.entry_samples ||= packet.json_hash.dup # Grab all the samples from the first packet
|
241
|
+
if state.first
|
242
|
+
state.raw_values = packet.read_all(:RAW, nil, packet.read_all_names(:RAW)).select { |key, value| value.is_a?(Numeric) }
|
243
|
+
state.raw_keys ||= state.raw_values.keys
|
244
|
+
state.converted_values = packet.read_all(:CONVERTED, nil, packet.read_all_names(:CONVERTED)).select { |key, value| value.is_a?(Numeric) }
|
245
|
+
state.converted_keys ||= state.converted_values.keys
|
246
|
+
else
|
247
|
+
state.raw_values = packet.read_all(:RAW, nil, state.raw_keys).select { |key, value| value.is_a?(Numeric) }
|
248
|
+
state.converted_values = packet.read_all(:CONVERTED, nil, state.converted_keys).select { |key, value| value.is_a?(Numeric) }
|
197
249
|
end
|
250
|
+
else
|
251
|
+
# Hour or Day
|
252
|
+
state.entry_samples ||= extract_entry_samples(packet)
|
253
|
+
if state.first
|
254
|
+
state.raw_max_values = packet.read_all(:RAW, :MAX, packet.read_all_names(:RAW, :MAX))
|
255
|
+
state.raw_keys = state.raw_max_values.keys
|
256
|
+
state.converted_max_values = packet.read_all(:CONVERTED, :MAX, packet.read_all_names(:CONVERTED, :MAX))
|
257
|
+
state.converted_keys = state.converted_max_values.keys
|
258
|
+
else
|
259
|
+
state.raw_max_values = packet.read_all(:RAW, :MAX, state.raw_keys)
|
260
|
+
state.converted_max_values = packet.read_all(:CONVERTED, :MAX, state.converted_keys)
|
261
|
+
end
|
262
|
+
state.raw_min_values = packet.read_all(:RAW, :MIN, state.raw_keys)
|
263
|
+
state.raw_avg_values = packet.read_all(:RAW, :AVG, state.raw_keys)
|
264
|
+
state.raw_stddev_values = packet.read_all(:RAW, :STDDEV, state.raw_keys)
|
265
|
+
state.converted_min_values = packet.read_all(:CONVERTED, :MIN, state.converted_keys)
|
266
|
+
state.converted_avg_values = packet.read_all(:CONVERTED, :AVG, state.converted_keys)
|
267
|
+
state.converted_stddev_values = packet.read_all(:CONVERTED, :STDDEV, state.converted_keys)
|
198
268
|
end
|
199
269
|
|
200
|
-
|
201
|
-
|
202
|
-
|
270
|
+
reduced = state.reduced
|
271
|
+
if type == 'minute'
|
272
|
+
# Update statistics for this packet's raw values
|
273
|
+
state.raw_values.each do |key, value|
|
203
274
|
reduced["#{key}__VALS"] ||= []
|
204
275
|
reduced["#{key}__VALS"] << value
|
205
|
-
reduced["#{key}
|
206
|
-
reduced["#{key}
|
207
|
-
reduced["#{key}
|
208
|
-
reduced["#{key}
|
209
|
-
else
|
210
|
-
reduced[key] ||= value
|
211
|
-
reduced[key] = value if key.match(/_MIN$/) && value < reduced[key]
|
212
|
-
reduced[key] = value if key.match(/_MAX$/) && value > reduced[key]
|
213
|
-
if key.match(/_AVG$/)
|
214
|
-
reduced["#{key}__VALS"] ||= []
|
215
|
-
reduced["#{key}__VALS"] << value
|
216
|
-
end
|
217
|
-
if key.match(/_STDDEV$/)
|
218
|
-
reduced["#{key}__VALS"] ||= []
|
219
|
-
reduced["#{key}__VALS"] << value
|
220
|
-
end
|
221
|
-
if key.match(/_SAMPLES$/)
|
222
|
-
reduced["#{key}__VALS"] ||= []
|
223
|
-
reduced["#{key}__VALS"] << value
|
224
|
-
end
|
276
|
+
reduced["#{key}__N"] ||= value
|
277
|
+
reduced["#{key}__N"] = value if value < reduced["#{key}__N"]
|
278
|
+
reduced["#{key}__X"] ||= value
|
279
|
+
reduced["#{key}__X"] = value if value > reduced["#{key}__X"]
|
225
280
|
end
|
281
|
+
|
282
|
+
# Update statistics for this packet's converted values
|
283
|
+
state.converted_values.each do |key, value|
|
284
|
+
reduced["#{key}__CVALS"] ||= []
|
285
|
+
reduced["#{key}__CVALS"] << value
|
286
|
+
reduced["#{key}__CN"] ||= value
|
287
|
+
reduced["#{key}__CN"] = value if value < reduced["#{key}__CN"]
|
288
|
+
reduced["#{key}__CX"] ||= value
|
289
|
+
reduced["#{key}__CX"] = value if value > reduced["#{key}__CX"]
|
290
|
+
end
|
291
|
+
else
|
292
|
+
# Update statistics for this packet's raw values
|
293
|
+
state.raw_max_values.each do |key, value|
|
294
|
+
max_key = "#{key}__X"
|
295
|
+
reduced[max_key] ||= value
|
296
|
+
reduced[max_key] = value if value > reduced[max_key]
|
297
|
+
end
|
298
|
+
state.raw_min_values.each do |key, value|
|
299
|
+
min_key = "#{key}__N"
|
300
|
+
reduced[min_key] ||= value
|
301
|
+
reduced[min_key] = value if value < reduced[min_key]
|
302
|
+
end
|
303
|
+
state.raw_avg_values.each do |key, value|
|
304
|
+
avg_values_key = "#{key}__AVGVALS"
|
305
|
+
reduced[avg_values_key] ||= []
|
306
|
+
reduced[avg_values_key] << value
|
307
|
+
end
|
308
|
+
state.raw_stddev_values.each do |key, value|
|
309
|
+
stddev_values_key = "#{key}__STDDEVVALS"
|
310
|
+
reduced[stddev_values_key] ||= []
|
311
|
+
reduced[stddev_values_key] << value
|
312
|
+
end
|
313
|
+
|
314
|
+
# Update statistics for this packet's converted values
|
315
|
+
state.converted_max_values.each do |key, value|
|
316
|
+
max_key = "#{key}__CX"
|
317
|
+
reduced[max_key] ||= value
|
318
|
+
reduced[max_key] = value if value > reduced[max_key]
|
319
|
+
end
|
320
|
+
state.converted_min_values.each do |key, value|
|
321
|
+
min_key = "#{key}__CN"
|
322
|
+
reduced[min_key] ||= value
|
323
|
+
reduced[min_key] = value if value < reduced[min_key]
|
324
|
+
end
|
325
|
+
state.converted_avg_values.each do |key, value|
|
326
|
+
avg_values_key = "#{key}__CAVGVALS"
|
327
|
+
reduced[avg_values_key] ||= []
|
328
|
+
reduced[avg_values_key] << value
|
329
|
+
end
|
330
|
+
state.converted_stddev_values.each do |key, value|
|
331
|
+
stddev_values_key = "#{key}__CSTDDEVVALS"
|
332
|
+
reduced[stddev_values_key] ||= []
|
333
|
+
reduced[stddev_values_key] << value
|
334
|
+
end
|
335
|
+
|
336
|
+
reduced["_NUM_SAMPLES__VALS"] ||= []
|
337
|
+
reduced["_NUM_SAMPLES__VALS"] << packet.read('_NUM_SAMPLES')
|
226
338
|
end
|
339
|
+
|
340
|
+
state.first = false
|
227
341
|
end
|
228
342
|
file.delete # Remove the local copy
|
229
343
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
344
|
+
write_all_entries(reducer_state, plw, type, target_name, stored)
|
345
|
+
true
|
346
|
+
rescue => e
|
347
|
+
if file.local_path and File.exist?(file.local_path)
|
348
|
+
Logger.error("Reducer Error: #{filename}: #{File.size(file.local_path)} bytes: \n#{e.formatted}")
|
349
|
+
else
|
350
|
+
Logger.error("Reducer Error: #{filename}: \n#{e.formatted}")
|
235
351
|
end
|
352
|
+
false
|
353
|
+
end
|
236
354
|
|
237
|
-
|
238
|
-
|
239
|
-
|
355
|
+
def check_new_file(reducer_state, plw, type, target_name, stored, current_time, file_nanoseconds)
|
356
|
+
plw_first_time_nsec = plw.buffered_first_time_nsec
|
357
|
+
if plw_first_time_nsec && ((current_time - plw_first_time_nsec) >= file_nanoseconds)
|
358
|
+
# Write out all entries in progress
|
359
|
+
write_all_entries(reducer_state, plw, type, target_name, stored)
|
360
|
+
reducer_state.clear
|
361
|
+
plw.start_new_file(true) # Automatically closes the current file
|
362
|
+
return true
|
363
|
+
else
|
364
|
+
return false
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
def setup_state(reducer_state, packet, current_time)
|
369
|
+
# Get state for this packet
|
370
|
+
state = reducer_state[packet.packet_name]
|
371
|
+
unless state
|
372
|
+
state = ReducerState.new
|
373
|
+
reducer_state[packet.packet_name] = state
|
374
|
+
end
|
375
|
+
|
376
|
+
# Update state timestamps
|
377
|
+
state.previous_time = state.current_time # Will be nil first packet
|
378
|
+
state.current_time = current_time
|
379
|
+
state.entry_time ||= state.current_time # Sets the entry time from the first packet
|
380
|
+
return state
|
381
|
+
end
|
382
|
+
|
383
|
+
def write_all_entries(reducer_state, plw, type, target_name, stored)
|
384
|
+
reducer_state.each do |packet_name, state|
|
385
|
+
write_entry(state, plw, type, target_name, packet_name, stored)
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def write_entry(state, plw, type, target_name, packet_name, stored)
|
390
|
+
return unless state.reduced.length > 0
|
391
|
+
reduce(type, state.raw_keys, state.converted_keys, state.reduced)
|
392
|
+
state.reduced.merge!(state.entry_samples)
|
393
|
+
time = state.entry_time
|
394
|
+
data = JSON.generate(state.reduced.as_json(:allow_nan => true))
|
395
|
+
if type == "minute"
|
396
|
+
redis_topic, redis_offset = TelemetryReducedMinuteTopic.write(target_name: target_name, packet_name: packet_name, stored: stored, time: time, data: data, scope: @scope)
|
397
|
+
elsif type == "hour"
|
398
|
+
redis_topic, redis_offset = TelemetryReducedHourTopic.write(target_name: target_name, packet_name: packet_name, stored: stored, time: time, data: data, scope: @scope)
|
399
|
+
else
|
400
|
+
redis_topic, redis_offset = TelemetryReducedDayTopic.write(target_name: target_name, packet_name: packet_name, stored: stored, time: time, data: data, scope: @scope)
|
401
|
+
end
|
402
|
+
plw.buffered_write(
|
240
403
|
:JSON_PACKET,
|
241
404
|
:TLM,
|
242
405
|
target_name,
|
243
406
|
packet_name,
|
244
|
-
|
245
|
-
|
246
|
-
|
407
|
+
time,
|
408
|
+
stored,
|
409
|
+
data,
|
410
|
+
nil,
|
411
|
+
redis_topic,
|
412
|
+
redis_offset
|
247
413
|
)
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
Logger.error("Reducer Error: #{filename}:(Not Retrieved): \n#{e.formatted}")
|
254
|
-
end
|
255
|
-
false
|
414
|
+
|
415
|
+
# Reset necessary state variables
|
416
|
+
state.entry_time = state.current_time # This packet starts the next entry
|
417
|
+
state.entry_samples = nil
|
418
|
+
state.reduced = {}
|
256
419
|
end
|
257
420
|
|
258
|
-
def reduce(type,
|
421
|
+
def reduce(type, raw_keys, converted_keys, reduced)
|
259
422
|
# We've collected all the values so calculate the AVG and STDDEV
|
260
423
|
if type == 'minute'
|
261
|
-
|
262
|
-
reduced["
|
263
|
-
reduced["#{key}
|
424
|
+
raw_keys.each do |key|
|
425
|
+
reduced["_NUM_SAMPLES"] ||= reduced["#{key}__VALS"].length # Keep a single sample count per packet
|
426
|
+
reduced["#{key}__A"], reduced["#{key}__S"] =
|
264
427
|
Math.stddev_population(reduced["#{key}__VALS"])
|
265
|
-
|
266
428
|
# Remove the raw values as they're only used for AVG / STDDEV calculation
|
267
429
|
reduced.delete("#{key}__VALS")
|
268
430
|
end
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
reduced["#{key}__VALS"].each_with_index do |val, i|
|
278
|
-
weighted_sum += (val * samples[i])
|
279
|
-
end
|
280
|
-
reduced[key] = weighted_sum / samples.sum
|
281
|
-
when /_SAMPLES$/
|
282
|
-
reduced[key] = reduced["#{base_name}_SAMPLES__VALS"].sum
|
283
|
-
when /_STDDEV$/
|
284
|
-
# Do the STDDEV calc last so we can use the previously calculated AVG
|
285
|
-
# See https://math.stackexchange.com/questions/1547141/aggregating-standard-deviation-to-a-summary-point
|
286
|
-
samples = reduced["#{base_name}_SAMPLES__VALS"]
|
287
|
-
avg = reduced["#{base_name}_AVG__VALS"]
|
288
|
-
s2 = 0
|
289
|
-
reduced["#{key}__VALS"].each_with_index do |val, i|
|
290
|
-
# puts "i:#{i} val:#{val} samples[i]:#{samples[i]} avg[i]:#{avg[i]}"
|
291
|
-
s2 += (samples[i] * avg[i]**2 + val**2)
|
292
|
-
end
|
293
|
-
|
294
|
-
# Note: For very large numbers with very small deviations this sqrt can fail.
|
295
|
-
# If so then just set the stddev to 0.
|
296
|
-
begin
|
297
|
-
reduced[key] =
|
298
|
-
Math.sqrt(s2 / samples.sum - reduced["#{base_name}_AVG"])
|
299
|
-
rescue Exception
|
300
|
-
reduced[key] = 0.0
|
301
|
-
end
|
302
|
-
end
|
431
|
+
|
432
|
+
converted_keys.each do |key|
|
433
|
+
reduced["_NUM_SAMPLES"] ||= reduced["#{key}__CVALS"].length # Keep a single sample count per packet
|
434
|
+
reduced["#{key}__CA"], reduced["#{key}__CS"] =
|
435
|
+
Math.stddev_population(reduced["#{key}__CVALS"])
|
436
|
+
|
437
|
+
# Remove the converted values as they're only used for AVG / STDDEV calculation
|
438
|
+
reduced.delete("#{key}__CVALS")
|
303
439
|
end
|
304
|
-
|
305
|
-
|
306
|
-
|
440
|
+
else
|
441
|
+
samples = reduced["_NUM_SAMPLES__VALS"]
|
442
|
+
samples_sum = samples.sum
|
443
|
+
reduced["_NUM_SAMPLES"] = samples_sum
|
444
|
+
reduced.delete("_NUM_SAMPLES__VALS")
|
445
|
+
|
446
|
+
raw_keys.each { |key| reduce_running(key, reduced, samples, samples_sum, "__A", "__S", "__AVGVALS", "__STDDEVVALS") }
|
447
|
+
converted_keys.each { |key| reduce_running(key, reduced, samples, samples_sum, "__CA", "__CS", "__CAVGVALS", "__CSTDDEVVALS") }
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
def reduce_running(key, reduced, samples, samples_sum, avg_key, stddev_key, avgvals_key, stddevvals_key)
|
452
|
+
# Calculate Average
|
453
|
+
weighted_sum = 0
|
454
|
+
avg = reduced["#{key}#{avgvals_key}"]
|
455
|
+
avg.each_with_index do |val, i|
|
456
|
+
weighted_sum += (val * samples[i])
|
457
|
+
end
|
458
|
+
reduced["#{key}#{avg_key}"] = weighted_sum / samples_sum
|
459
|
+
|
460
|
+
# Do the STDDEV calc last so we can use the previously calculated AVG
|
461
|
+
# See https://math.stackexchange.com/questions/1547141/aggregating-standard-deviation-to-a-summary-point
|
462
|
+
s2 = 0
|
463
|
+
reduced["#{key}#{stddevvals_key}"].each_with_index do |val, i|
|
464
|
+
# puts "i:#{i} val:#{val} samples[i]:#{samples[i]} avg[i]:#{avg[i]}"
|
465
|
+
s2 += (samples[i] * avg[i]**2 + val**2)
|
466
|
+
end
|
467
|
+
|
468
|
+
# Note: For very large numbers with very small deviations this sqrt can fail.
|
469
|
+
# If so then just set the stddev to 0.
|
470
|
+
begin
|
471
|
+
reduced["#{key}#{stddev_key}"] =
|
472
|
+
Math.sqrt(s2 / samples_sum - reduced["#{key}#{avg_key}"])
|
473
|
+
rescue Exception
|
474
|
+
reduced["#{key}#{stddev_key}"] = 0.0
|
475
|
+
end
|
476
|
+
|
477
|
+
reduced.delete("#{key}#{avgvals_key}")
|
478
|
+
reduced.delete("#{key}#{stddevvals_key}")
|
479
|
+
end
|
480
|
+
|
481
|
+
# Extract just the not reduced fields from a JsonPacket
|
482
|
+
def extract_entry_samples(packet)
|
483
|
+
result = {}
|
484
|
+
packet.json_hash.each do |key, value|
|
485
|
+
key_split = key.split('__')
|
486
|
+
if (not key_split[1] or not ['N', 'X', 'A', 'S'].include?(key_split[1][-1])) and key != '_NUM_SAMPLES'
|
487
|
+
result[key] = value
|
307
488
|
end
|
308
489
|
end
|
490
|
+
return result
|
309
491
|
end
|
492
|
+
|
310
493
|
end
|
311
494
|
end
|
312
495
|
|
@@ -16,6 +16,9 @@
|
|
16
16
|
# Modified by OpenC3, Inc.
|
17
17
|
# All changes Copyright 2022, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
|
+
#
|
20
|
+
# This file may also be used under the terms of a commercial license
|
21
|
+
# if purchased from OpenC3, Inc.
|
19
22
|
|
20
23
|
require 'openc3/microservices/interface_microservice'
|
21
24
|
|
@@ -16,6 +16,9 @@
|
|
16
16
|
# Modified by OpenC3, Inc.
|
17
17
|
# All changes Copyright 2022, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
|
+
#
|
20
|
+
# This file may also be used under the terms of a commercial license
|
21
|
+
# if purchased from OpenC3, Inc.
|
19
22
|
|
20
23
|
require 'openc3/microservices/microservice'
|
21
24
|
require 'openc3/topics/topic'
|
@@ -41,36 +44,35 @@ module OpenC3
|
|
41
44
|
end
|
42
45
|
|
43
46
|
def run
|
44
|
-
|
47
|
+
setup_tlws()
|
45
48
|
while true
|
46
49
|
break if @cancel_thread
|
47
50
|
|
48
51
|
Topic.read_topics(@topics) do |topic, msg_id, msg_hash, redis|
|
49
52
|
break if @cancel_thread
|
50
53
|
|
51
|
-
log_data(
|
54
|
+
log_data(topic, msg_id, msg_hash, redis)
|
52
55
|
end
|
53
56
|
end
|
54
57
|
end
|
55
58
|
|
56
59
|
def setup_tlws
|
57
|
-
tlws = {}
|
60
|
+
@tlws = {}
|
58
61
|
@topics.each do |topic|
|
59
62
|
topic_split = topic.gsub(/{|}/, '').split("__") # Remove the redis hashtag curly braces
|
60
63
|
scope = topic_split[0]
|
61
64
|
log_name = topic_split[1]
|
62
65
|
remote_log_directory = "#{scope}/text_logs/#{log_name}"
|
63
|
-
tlws[topic] = TextLogWriter.new(remote_log_directory, true, @cycle_time, @cycle_size,
|
66
|
+
@tlws[topic] = TextLogWriter.new(remote_log_directory, true, @cycle_time, @cycle_size, nil, nil, false)
|
64
67
|
end
|
65
|
-
return tlws
|
66
68
|
end
|
67
69
|
|
68
|
-
def log_data(
|
70
|
+
def log_data(topic, msg_id, msg_hash, redis)
|
69
71
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
70
72
|
keys = msg_hash.keys
|
71
73
|
keys.delete("time")
|
72
74
|
entry = keys.reduce("") { |data, key| data + "#{key}: #{msg_hash[key]}\t" }
|
73
|
-
tlws[topic].write(msg_hash["time"].to_i, entry, msg_id)
|
75
|
+
@tlws[topic].write(msg_hash["time"].to_i, entry, topic, msg_id)
|
74
76
|
@count += 1
|
75
77
|
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
76
78
|
@metric.add_sample(name: "log_duration_seconds", value: diff, labels: {})
|
@@ -78,6 +80,19 @@ module OpenC3
|
|
78
80
|
@error = err
|
79
81
|
Logger.error("#{@name} error: #{err.formatted}")
|
80
82
|
end
|
83
|
+
|
84
|
+
def shutdown
|
85
|
+
# Make sure all the existing logs are properly closed down
|
86
|
+
threads = []
|
87
|
+
@tlws.each do |topic, tlw|
|
88
|
+
threads.concat(tlw.shutdown)
|
89
|
+
end
|
90
|
+
# Wait for all the logging threads to move files to buckets
|
91
|
+
threads.flatten.compact.each do |thread|
|
92
|
+
thread.join
|
93
|
+
end
|
94
|
+
super()
|
95
|
+
end
|
81
96
|
end
|
82
97
|
end
|
83
98
|
|