rb_falcon_logger 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +23 -0
- data/README.md +215 -0
- data/lib/gem_source/logger.rb +870 -0
- data/lib/rb_falcon_logger.rb +3 -0
- data/lib/version.rb +3 -0
- metadata +49 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0bad75b78e2dc2cc1edc991a6e7fc912937e45252605057c324ce54a630120f2
|
4
|
+
data.tar.gz: 250fe6f8ec33ece120659375e8b2869a8046c28bbd31715ba4d9b6c4824e8ada
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 70f5902ea03b8c144d6845da7514112602a859c1e8249a84dbb38df012269db05b069aea38bcc35b51bfd1027ed5d1ba2f16cc01057c4c23680c7b24c203aa1d
|
7
|
+
data.tar.gz: f6da83bc50a6ccd04deee151da80e138aa3e86189202b2049f58d68fcda181c18fca8f55d4bf7f9447cd6f5aaae78188527f3f6f884a8d648d21feb6e688f6f1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) since 2025: rb-falcon-logger Ruby Gem
|
4
|
+
description: fast logger with multiple modes and formats
|
5
|
+
author: J. Arrizza email: cppgent0@gmail.com
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
9
|
+
in the Software without restriction, including without limitation the rights
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
12
|
+
furnished to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
15
|
+
copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
* website: <https://arrizza.com/rb-falcon-logger.html>
|
2
|
+
* installation: see <https://arrizza.com/setup-common.html>
|
3
|
+
|
4
|
+
## Summary
|
5
|
+
|
6
|
+
This is a ruby gem that provides a way to run a fast logger.
|
7
|
+
see <https://arrizza.com/python-falcon-logger.html> for a python version
|
8
|
+
|
9
|
+
## Sample code
|
10
|
+
|
11
|
+
see src/logger_tester.rb for a full example
|
12
|
+
|
13
|
+
Use doit script to run the logger.
|
14
|
+
|
15
|
+
TODO logger_tester args
|
16
|
+
TODO multithreaded_tester
|
17
|
+
|
18
|
+
## parameters and functions
|
19
|
+
|
20
|
+
Use these on the logger creation: ```@log = FalconLogger(path: etc, max_entries: etc, mode: etc.)```
|
21
|
+
|
22
|
+
* ```path: nil``` : (default) write to stdout
|
23
|
+
* ```path: 'path/to/file'``` : write to the given file
|
24
|
+
* ```max_entries: 10```: flush the queue when this number of log entries is reached.
|
25
|
+
* ```loop_delay: 0.250```: check the queue this often. The longer the delay, the fast it runs.
|
26
|
+
* Note: use max_entries: 1 and loop_delay: 0.001, to flush the queue as often as possible
|
27
|
+
* ```set_verbose(true)``` - (default) print all log lines to stdout/file.
|
28
|
+
* ```set_verbose(false)``` - only print err(), critical(), exception(), and bug() lines
|
29
|
+
* ```@log.set_max_dots(num)``` set the number of dots to print before a newline is printed
|
30
|
+
* use ```@log.save``` to force the queue to be saved. Generally not recommended.
|
31
|
+
* use ```@log.term``` to clear out the queue and gracefully end the background thread
|
32
|
+
|
33
|
+
There are 3 modes: ```FalconLogger(mode: 'normal')```
|
34
|
+
|
35
|
+
* nil or 'normal': (default) writes a line to stdout or the file. See below for outputs
|
36
|
+
* 'ut' or 'mock': useful in UTs. These do not write to stdout or to a file.
|
37
|
+
* The lines are saved in an internal list accessible by: ```@log.ut_lines```.
|
38
|
+
* Use ```@log.ut_clear``` or ```@log.ut_lines = []``` to empty it.
|
39
|
+
* 'null': is useful when you don't want any output. No stdout, no file, no ut_lines.
|
40
|
+
|
41
|
+
There are 3 formats: 'elapsed' (default), 'prefix', 'none'
|
42
|
+
|
43
|
+
* Use ```@log.set_format(fmt)``` to set the format to fmt
|
44
|
+
|
45
|
+
## 'elapsed' format outputs
|
46
|
+
|
47
|
+
These contain:
|
48
|
+
|
49
|
+
* the number of MM:SS.nnn milliseconds since the last log line
|
50
|
+
* if this the first log line, the current date time stamp is automatically printed:
|
51
|
+
```DTS 2025/05/11 16:21:43.170```
|
52
|
+
* if an hour goes by since the last DTS, then it is automatically printed
|
53
|
+
* a prefix indicating the type of log line error, OK, Debug, etc.
|
54
|
+
|
55
|
+
```text
|
56
|
+
@log.set_format('elapsed') # the default format
|
57
|
+
|
58
|
+
# idx = 2
|
59
|
+
|
60
|
+
# === showing with elapsed time delays
|
61
|
+
# === @log.start("#{idx}:", 'start of dts values')
|
62
|
+
# === sleep(0.250)
|
63
|
+
# === @log.line("#{idx}:", 'start + 250ms')
|
64
|
+
# === sleep(0.123)
|
65
|
+
# === @log.line("#{idx}:", 'start + 373ms')
|
66
|
+
00:00.000 ==== 2: start of dts values
|
67
|
+
00:00.250 2: start + 250ms
|
68
|
+
00:00.373 2: start + 373ms
|
69
|
+
|
70
|
+
# === the automatic DTS line when 1 hour has elapsed or at the beginning
|
71
|
+
# === @log.start("#{idx}:", 'start')
|
72
|
+
DTS 2025/05/21 19:01:11.154
|
73
|
+
00:00.000 ==== 2: start
|
74
|
+
|
75
|
+
# === @log.line("#{idx}:", 'line')
|
76
|
+
00:00.000 2: line
|
77
|
+
|
78
|
+
# === @log.highlight("#{idx}:", 'highlight')
|
79
|
+
00:00.000 ---> 2: highlight
|
80
|
+
|
81
|
+
# === @log.ok("#{idx}:", 'ok')
|
82
|
+
00:00.000 OK 2: ok
|
83
|
+
|
84
|
+
# === @log.err("#{idx}:", 'err')
|
85
|
+
00:00.000 ERR 2: err
|
86
|
+
|
87
|
+
# === @log.warn("#{idx}:", 'warn')
|
88
|
+
00:00.000 WARN 2: warn
|
89
|
+
|
90
|
+
# === @log.bug("#{idx}:", 'bug')
|
91
|
+
00:00.000 BUG 2: bug
|
92
|
+
|
93
|
+
# === @log.dbg("#{idx}:", 'dbg')
|
94
|
+
00:00.000 DBG 2: dbg
|
95
|
+
|
96
|
+
# === @log.raw("#{idx}", 'raw', 'line')
|
97
|
+
2 raw line
|
98
|
+
|
99
|
+
# === @log.output(nil, "#{idx}:", 'output (line nil)')
|
100
|
+
# === @log.output(21, "#{idx}:", 'output (line 21)')
|
101
|
+
00:00.000 -- 2: output (line nil)
|
102
|
+
00:00.000 -- 21] 2: output (line 21)
|
103
|
+
|
104
|
+
#=== lines = ["#{idx}: num_output (line 1)", "#{idx}: num_output (line 2)"]
|
105
|
+
#=== @log.num_output(lines)
|
106
|
+
00:00.000 -- 1] 2: num_output (line 1)
|
107
|
+
00:00.000 -- 2] 2: num_output (line 2)
|
108
|
+
|
109
|
+
# === @log.check(true, "#{idx}:", 'check true')
|
110
|
+
# === @log.check(false, "#{idx}:", 'check false')
|
111
|
+
00:00.000 OK 2: check true
|
112
|
+
00:00.000 ERR 2: check false
|
113
|
+
|
114
|
+
# === lines = ["#{idx}: check_all (line 1)", "#{idx}: check_all (line 2)"]
|
115
|
+
# === @log.check_all(true, 'check_all true title', lines)
|
116
|
+
00:00.000 OK check_all true title: true
|
117
|
+
00:00.000 OK - 2: check_all (line 1)
|
118
|
+
00:00.000 OK - 2: check_all (line 2)
|
119
|
+
|
120
|
+
# === info = { 'key1' => ['val1'] }
|
121
|
+
# === @log.json(info, "#{idx}:", 'json', 'list (json/hash)')
|
122
|
+
00:00.000 2: json list (json/hash)
|
123
|
+
00:00.000 > {
|
124
|
+
00:00.000 > "key1": [
|
125
|
+
00:00.000 > "val1"
|
126
|
+
00:00.000 > ]
|
127
|
+
00:00.000 > }
|
128
|
+
|
129
|
+
#=== val = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11"
|
130
|
+
#=== @log.hex(val, "#{idx}:", 'hex long')
|
131
|
+
00:00.000 2: hex long
|
132
|
+
00:00.000 0 0x00: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
|
133
|
+
00:00.000 16 0x10: 10 11
|
134
|
+
|
135
|
+
# === @log.debug("#{idx}:", 'debug')
|
136
|
+
00:00.000 DBG 2: debug
|
137
|
+
|
138
|
+
# === @log.info("#{idx}:", 'info')
|
139
|
+
00:00.000 2: info
|
140
|
+
|
141
|
+
# === @log.warning("#{idx}:", 'warning')
|
142
|
+
00:00.000 WARN 2: warning
|
143
|
+
|
144
|
+
# === @log.error("#{idx}:", 'error')
|
145
|
+
00:00.000 ERR 2: error
|
146
|
+
|
147
|
+
# === @log.critical("#{idx}:", 'critical')
|
148
|
+
00:00.000 CRIT 2: critical
|
149
|
+
|
150
|
+
# === val = 5
|
151
|
+
# === begin
|
152
|
+
# === val /= 0
|
153
|
+
# === rescue ZeroDivisionError => e # <== note: use max_lines: 1 to reduce the amount of output you need
|
154
|
+
# === @log.exception(e)
|
155
|
+
# === end
|
156
|
+
# === @log.line("after excp; val=#{val}")
|
157
|
+
00:00.000 EXCP divided by 0
|
158
|
+
00:00.000 EXCP Backtrace:
|
159
|
+
00:00.000 EXCP <snip>/logger_tester.rb:178:in `/'
|
160
|
+
00:00.000 EXCP <snip>/logger_tester.rb:178:in `_log_exception'
|
161
|
+
00:00.000 EXCP <snip>/logger_tester.rb:88:in `block in run'
|
162
|
+
|
163
|
+
# === @log.full_dts
|
164
|
+
DTS 2025/05/11 16:21:43.170
|
165
|
+
```
|
166
|
+
|
167
|
+
## 'prefix' format outputs
|
168
|
+
|
169
|
+
These are the same as elapsed format, except no elapsed times.
|
170
|
+
Use ```./doit normal prefix``` to see an example.
|
171
|
+
|
172
|
+
```text
|
173
|
+
@log.set_format('prefix')
|
174
|
+
|
175
|
+
# === @log.ok("#{idx}:", 'ok')
|
176
|
+
OK 2: ok
|
177
|
+
# === @log.err("#{idx}:", 'err')
|
178
|
+
ERR 2: err
|
179
|
+
<snip>
|
180
|
+
```
|
181
|
+
|
182
|
+
## 'none' format outputs
|
183
|
+
|
184
|
+
These are the same as elapsed/prefix format, except no elapsed times or prefixes
|
185
|
+
Use ```./doit normal none``` to see an example.
|
186
|
+
|
187
|
+
```text
|
188
|
+
@log.set_format('none')
|
189
|
+
|
190
|
+
# === @log.ok("#{idx}:", 'ok')
|
191
|
+
2: ok
|
192
|
+
# === @log.err("#{idx}:", 'err')
|
193
|
+
2: err
|
194
|
+
<snip>
|
195
|
+
```
|
196
|
+
|
197
|
+
## dots
|
198
|
+
|
199
|
+
To put out a series of dots to show progress, use ```@log.dot```.
|
200
|
+
|
201
|
+
Periodically a newline is printed.
|
202
|
+
The default is 25, use ```@log.set_max_dots(nn)``` to change it
|
203
|
+
|
204
|
+
## ./doit examples
|
205
|
+
|
206
|
+
* Use ```./doit file``` to generate a file ```out/sample.log```
|
207
|
+
* Use ```./doit null``` to use ```mode: 'null'```, no output, no file generated
|
208
|
+
* Use ```./doit ut``` or ```./doit mock``` to use ```mode: 'ut'```. This mode can be used in unit tests.
|
209
|
+
* Use ```./doit thread``` to see an example of a multithreaded use of the logger. The default is:
|
210
|
+
* 100 client threads
|
211
|
+
* each client thread putting in 1000 entries onto the queue.
|
212
|
+
* There are random delays between each push() between 0 and 250ms
|
213
|
+
* each client thread logs it is putting an entry on the queue using FalconLogger
|
214
|
+
* 1 background thread checking that queue, and printing any entries using FalconLogger
|
215
|
+
* This takes just over 2m (on my PC)
|
@@ -0,0 +1,870 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
# import atexit
|
5
|
+
# import threading
|
6
|
+
|
7
|
+
# -------------------
|
8
|
+
## Sample gem source
|
9
|
+
class FalconLogger
|
10
|
+
## logging formats
|
11
|
+
class LogFormat
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
## logging format with elapsed time and prefixes
|
15
|
+
ELAPSED = 1
|
16
|
+
## logging format with prefixes only
|
17
|
+
PREFIX = 2
|
18
|
+
## logging format with no prefixes or elapsed time
|
19
|
+
NONE = 3
|
20
|
+
end
|
21
|
+
|
22
|
+
## configuration in for bg thread runner
|
23
|
+
class RunnerCfg
|
24
|
+
## the maximum entries to hold in the queue before saving to the file
|
25
|
+
attr_accessor :max_entries
|
26
|
+
## the maximum number of loops before the queue is emptied
|
27
|
+
attr_accessor :max_count
|
28
|
+
## the delay between checking the queue for entries to save
|
29
|
+
attr_accessor :loop_delay
|
30
|
+
|
31
|
+
# -------------------
|
32
|
+
def initialize
|
33
|
+
@max_entries = 0
|
34
|
+
@max_count = 0
|
35
|
+
@loop_delay = 0.0
|
36
|
+
end
|
37
|
+
|
38
|
+
# -------------------
|
39
|
+
def copy_from(copy_obj)
|
40
|
+
@max_entries = copy_obj.max_entries
|
41
|
+
@max_count = copy_obj.max_count
|
42
|
+
@loop_delay = copy_obj.loop_delay
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
## holds verbosity
|
47
|
+
attr_writer :verbose
|
48
|
+
|
49
|
+
## UT only: holds all lines printed
|
50
|
+
attr_accessor :ut_lines
|
51
|
+
|
52
|
+
###
|
53
|
+
## constructor
|
54
|
+
# @param path nil for stdout, or full path to the logger file
|
55
|
+
# @param max_entries (optional) maximum number of entries before a flush is done; default 10
|
56
|
+
# @param loop_delay (optional) time between checking queue; default 0.250 seconds
|
57
|
+
# @param mode (optional) logging mode:
|
58
|
+
# nil or "normal": (default) log all lines as set by configuration, format, etc.
|
59
|
+
# "ut" or "mock": for UT purposes, saves lines in ut_lines array
|
60
|
+
# "null": do no logging; see verbosity for an alternative
|
61
|
+
def initialize(path: nil,
|
62
|
+
max_entries: 10,
|
63
|
+
loop_delay: 0.250,
|
64
|
+
mode: nil)
|
65
|
+
## the full path to the log file (if any)
|
66
|
+
@path = path
|
67
|
+
## file pointer to destination file or stdout
|
68
|
+
@fp = nil
|
69
|
+
## holds the logging mode (nil, normal, ut, etc.
|
70
|
+
@logging_mode = mode
|
71
|
+
## holds the function that handles the logging of the current mode and format
|
72
|
+
@log_it = nil
|
73
|
+
|
74
|
+
## flag to log to stdout or not
|
75
|
+
@verbose = true
|
76
|
+
## for UT only
|
77
|
+
@ut_mode = false
|
78
|
+
## for UT only
|
79
|
+
@ut_lines = []
|
80
|
+
|
81
|
+
# === log formatting related
|
82
|
+
|
83
|
+
## verbosity; if true print all lines, if not print only errors, excp ad bug lines
|
84
|
+
@verbose = true
|
85
|
+
## the log display format to use; default: elapsed time + prefixes
|
86
|
+
@log_format = LogFormat::ELAPSED
|
87
|
+
## holds the last time a full DTS was written to the log;
|
88
|
+
# printed at the beginning and once per hour
|
89
|
+
@start_time = Time.at(0.0)
|
90
|
+
## current number of dots printed
|
91
|
+
@dots = 0
|
92
|
+
## max number of dots to display
|
93
|
+
@max_dots = 25
|
94
|
+
|
95
|
+
# === runner() related
|
96
|
+
## configuration values used by runner()
|
97
|
+
@runner_cfg = nil
|
98
|
+
## backup of runner_cfg
|
99
|
+
@backup_cfg = nil
|
100
|
+
## the bg thread used to run
|
101
|
+
@thread = nil
|
102
|
+
## the queue used
|
103
|
+
@queue = nil
|
104
|
+
## flag to the thread to end the loop
|
105
|
+
@finished = false
|
106
|
+
|
107
|
+
# === log_mode related
|
108
|
+
_init_cfg(max_entries, loop_delay)
|
109
|
+
if mode.nil? || mode == 'normal'
|
110
|
+
@logging_mode = 'normal'
|
111
|
+
@log_it = method(:_log_it_normal)
|
112
|
+
|
113
|
+
# initialize destination file pointer
|
114
|
+
@fp = $stdout
|
115
|
+
if @path.nil?
|
116
|
+
@fp = $stdout
|
117
|
+
else
|
118
|
+
@fp = File.open(@path, 'w', encoding: 'UTF-8')
|
119
|
+
end
|
120
|
+
_init_thread
|
121
|
+
elsif %w[ut mock].include?(mode)
|
122
|
+
_set_log_it_ut_fn
|
123
|
+
elsif mode == 'null'
|
124
|
+
@log_it = method(:_log_it_null)
|
125
|
+
else
|
126
|
+
raise(ArgumentError, "Unknown mode: \"#{mode}\", choose \"normal\", \"ut\", \"mock\" or \"null\"")
|
127
|
+
end
|
128
|
+
|
129
|
+
# try ensure at least one save() and thread cleanup is done
|
130
|
+
at_exit do
|
131
|
+
# uncomment to debug
|
132
|
+
# puts('in at_exit:')
|
133
|
+
term
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# --------------------
|
138
|
+
## initialize the configuration variables for the loop
|
139
|
+
#
|
140
|
+
# @param max_entries the max number of entries in the queue
|
141
|
+
# @param loop_delay how long to wait between checks of the queue
|
142
|
+
# @return nil
|
143
|
+
def _init_cfg(max_entries, loop_delay)
|
144
|
+
@runner_cfg = RunnerCfg.new
|
145
|
+
set_max_entries(max_entries)
|
146
|
+
set_loop_delay(loop_delay)
|
147
|
+
@backup_cfg = RunnerCfg.new
|
148
|
+
@backup_cfg.copy_from(@runner_cfg)
|
149
|
+
end
|
150
|
+
|
151
|
+
# --------------------
|
152
|
+
## initialize and start the thread
|
153
|
+
#
|
154
|
+
# @return nil
|
155
|
+
def _init_thread
|
156
|
+
@queue = Queue.new
|
157
|
+
@finished = false
|
158
|
+
|
159
|
+
@thread = Thread.new do
|
160
|
+
_runner
|
161
|
+
end
|
162
|
+
|
163
|
+
# wait for thread to start
|
164
|
+
sleep(0.100)
|
165
|
+
end
|
166
|
+
|
167
|
+
# --------------------
|
168
|
+
## UT only; clears ut_lines
|
169
|
+
# for backwards compatibility with python version
|
170
|
+
#
|
171
|
+
# @return nil
|
172
|
+
def ut_clear
|
173
|
+
@ut_lines = []
|
174
|
+
end
|
175
|
+
|
176
|
+
# --------------------
|
177
|
+
# for UT only; set the start_time to the given value
|
178
|
+
def ut_start_time(new_time)
|
179
|
+
if new_time.is_a?(Float)
|
180
|
+
@start_time = Time.at(new_time)
|
181
|
+
else
|
182
|
+
# assume it's a Time
|
183
|
+
@start_time = new_time
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# --------------------
|
188
|
+
## set verbosity
|
189
|
+
# for backwards compatibility with python version
|
190
|
+
#
|
191
|
+
# @param value (bool) verbosity level
|
192
|
+
# @return nil
|
193
|
+
def set_verbose(value)
|
194
|
+
@verbose = value
|
195
|
+
end
|
196
|
+
|
197
|
+
# --------------------
|
198
|
+
## set log line format.
|
199
|
+
#
|
200
|
+
# @param form (str) either "elapsed", "prefix", "non" or throws excp
|
201
|
+
# @return nil
|
202
|
+
def set_format(form)
|
203
|
+
if form == 'elapsed'
|
204
|
+
@log_format = LogFormat::ELAPSED
|
205
|
+
elsif form == 'prefix'
|
206
|
+
@log_format = LogFormat::PREFIX
|
207
|
+
elsif form == 'none'
|
208
|
+
@log_format = LogFormat::NONE
|
209
|
+
else
|
210
|
+
raise(ArgumentError, "Unknown format: \"#{form}\", choose \"elapsed\", \"prefix\" or \"none\"")
|
211
|
+
end
|
212
|
+
|
213
|
+
_set_log_it_ut_fn if %w[ut mock].include?(@logging_mode)
|
214
|
+
end
|
215
|
+
|
216
|
+
# --------------------
|
217
|
+
## set the log_it function to call based on the current logging format
|
218
|
+
#
|
219
|
+
# @return nil
|
220
|
+
def _set_log_it_ut_fn
|
221
|
+
if @log_format == LogFormat::ELAPSED
|
222
|
+
@log_it = method(:_log_it_ut_elapsed)
|
223
|
+
elsif @log_format == LogFormat::PREFIX
|
224
|
+
@log_it = method(:_log_it_ut_prefix)
|
225
|
+
elsif @log_format == LogFormat::NONE
|
226
|
+
@log_it = method(:_log_it_ut_none)
|
227
|
+
else
|
228
|
+
# :nocov:
|
229
|
+
# coverage: cannot be done in a UT
|
230
|
+
puts("BUG in _set_log_it_ut_fn : unhandled log format #{@log_format}")
|
231
|
+
# :nocov:
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# --------------------
|
236
|
+
## set max entries to allow in the queue before printing them
|
237
|
+
#
|
238
|
+
# @param value (int) number of entries; default: 10
|
239
|
+
# @return nil
|
240
|
+
def set_max_entries(value)
|
241
|
+
@runner_cfg.max_entries = value
|
242
|
+
raise(ArgumentError, 'max_entries must be greater than 0') if @runner_cfg.max_entries <= 0
|
243
|
+
end
|
244
|
+
|
245
|
+
# --------------------
|
246
|
+
## set loop delay to check the queue
|
247
|
+
#
|
248
|
+
# @param loop_delay (float) number of seconds; default: 0.250
|
249
|
+
# @return nil
|
250
|
+
def set_loop_delay(loop_delay)
|
251
|
+
@runner_cfg.loop_delay = loop_delay
|
252
|
+
raise(ArgumentError, 'loop_delay must be >= 0.001 seconds') if @runner_cfg.loop_delay < 0.001
|
253
|
+
|
254
|
+
# print every loop_delay seconds even if less than max_entries are in the queue
|
255
|
+
@runner_cfg.max_count = (1 / @runner_cfg.loop_delay).round(1).to_i
|
256
|
+
end
|
257
|
+
|
258
|
+
# --------------------
|
259
|
+
## set how many dots to print on one line before printing a newline
|
260
|
+
#
|
261
|
+
# @param value (int) number of dots
|
262
|
+
# @return nil
|
263
|
+
def set_max_dots(value)
|
264
|
+
@max_dots = value
|
265
|
+
raise(ArgumentError, 'max_dots must be greater than 0') unless @max_dots.positive?
|
266
|
+
end
|
267
|
+
|
268
|
+
# === cleanup functions
|
269
|
+
|
270
|
+
# --------------------
|
271
|
+
## terminate
|
272
|
+
# stop the thread, save any remaining line in the internal queue
|
273
|
+
#
|
274
|
+
# @return nil
|
275
|
+
def term
|
276
|
+
begin
|
277
|
+
# since this will be called during atexit() handling,
|
278
|
+
# stdout and/or file can be closed. Protect against this case.
|
279
|
+
_save
|
280
|
+
rescue Exception
|
281
|
+
# nothing to do
|
282
|
+
end
|
283
|
+
|
284
|
+
@finished = true
|
285
|
+
@thread.join(5.0) unless @thread.nil? || !@thread.alive?
|
286
|
+
end
|
287
|
+
|
288
|
+
# --------------------
|
289
|
+
## user can request a save at this point
|
290
|
+
#
|
291
|
+
# @return nil
|
292
|
+
attr_reader :save
|
293
|
+
|
294
|
+
# === log modes
|
295
|
+
|
296
|
+
# --------------------
|
297
|
+
## since it's normal mode, put the logging info on the queue.
|
298
|
+
#
|
299
|
+
# @param info the line info
|
300
|
+
# @return nil
|
301
|
+
def _log_it_normal(info)
|
302
|
+
@queue.push(info)
|
303
|
+
end
|
304
|
+
|
305
|
+
# --------------------
|
306
|
+
## since it's ut mode and no prefixes, add the line to ut_lines
|
307
|
+
#
|
308
|
+
# @param info the line info
|
309
|
+
# @return nil
|
310
|
+
def _log_it_ut_none(info)
|
311
|
+
return unless info[0] || info[1]
|
312
|
+
|
313
|
+
# always_print or verbose
|
314
|
+
if info[3].nil? && info[4] == [nil]
|
315
|
+
line = 'DTS'
|
316
|
+
elsif info[3] == '.' && info[4] == [nil]
|
317
|
+
line = '.'
|
318
|
+
else
|
319
|
+
line = info[4].join(' ')
|
320
|
+
end
|
321
|
+
@ut_lines.append(line)
|
322
|
+
end
|
323
|
+
|
324
|
+
# --------------------
|
325
|
+
## since it's ut mode and prefix mode add the line with prefix to ut_lines
|
326
|
+
#
|
327
|
+
# @param info the line info
|
328
|
+
# @return nil
|
329
|
+
def _log_it_ut_prefix(info)
|
330
|
+
return unless info[0] || info[1]
|
331
|
+
|
332
|
+
# always_print or verbose
|
333
|
+
prefix = info[3]
|
334
|
+
if prefix.nil? && info[4] == [nil]
|
335
|
+
line = 'DTS'
|
336
|
+
prefix = ' '
|
337
|
+
@ut_lines.append(format('%-4s %s', prefix, line))
|
338
|
+
elsif info[3] == '.' && info[4] == [nil]
|
339
|
+
@ut_lines.append('.')
|
340
|
+
elsif prefix.nil? # raw line
|
341
|
+
line = info[4].join(' ')
|
342
|
+
@ut_lines.append(line)
|
343
|
+
else
|
344
|
+
line = info[4].join(' ')
|
345
|
+
@ut_lines.append(format('%-4s %s', prefix, line))
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
# --------------------
|
350
|
+
## since it's ut mode and elapsed mode add the line with elapsed and prefix to ut_lines
|
351
|
+
#
|
352
|
+
# @param info the line info
|
353
|
+
# @return nil
|
354
|
+
def _log_it_ut_elapsed(info)
|
355
|
+
return unless info[0] || info[1]
|
356
|
+
|
357
|
+
# always_print or verbose
|
358
|
+
dts = info[2]
|
359
|
+
|
360
|
+
elapsed = Time.at(dts - @start_time)
|
361
|
+
if elapsed.to_f >= 3600.0
|
362
|
+
@start_time = Time.now
|
363
|
+
elapsed = 0.0
|
364
|
+
end
|
365
|
+
t_str = _get_elapsed_str(elapsed)
|
366
|
+
|
367
|
+
prefix = info[3]
|
368
|
+
if prefix.nil? && info[4] == [nil]
|
369
|
+
line = 'DTS'
|
370
|
+
prefix = ' '
|
371
|
+
@ut_lines.append(format('%-4s %s', prefix, line))
|
372
|
+
elsif info[3] == '.' && info[4] == [nil]
|
373
|
+
@ut_lines.append('.')
|
374
|
+
elsif prefix.nil? # raw line
|
375
|
+
line = info[4].join(' ')
|
376
|
+
@ut_lines.append(line)
|
377
|
+
else
|
378
|
+
line = info[4].join(' ')
|
379
|
+
@ut_lines.append(format('%s %-4s %s', t_str, prefix, line))
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
# --------------------
|
384
|
+
## since it's null mode, ignore the line
|
385
|
+
#
|
386
|
+
# @param info (ignored)
|
387
|
+
# @return nil
|
388
|
+
def _log_it_null(info)
|
389
|
+
# logging ignored
|
390
|
+
end
|
391
|
+
|
392
|
+
# === log lines with prefixes and elapsed times
|
393
|
+
|
394
|
+
# --------------------
|
395
|
+
## add an item to write the full date-time-stamp to the log
|
396
|
+
#
|
397
|
+
# @return nil
|
398
|
+
def full_dts
|
399
|
+
# the nil args/line causes the full dts to display
|
400
|
+
@log_it.call([false, @verbose, Time.now, nil, [nil]])
|
401
|
+
end
|
402
|
+
|
403
|
+
# -------------------
|
404
|
+
## write a "start" line with the given message
|
405
|
+
#
|
406
|
+
# @param args the message to log
|
407
|
+
# @return nil
|
408
|
+
def start(*args)
|
409
|
+
@log_it.call([false, @verbose, Time.now, '====', args].freeze)
|
410
|
+
end
|
411
|
+
|
412
|
+
# --------------------
|
413
|
+
## write a line with the given message
|
414
|
+
#
|
415
|
+
# @param args the message to log
|
416
|
+
# @return nil
|
417
|
+
def line(*args)
|
418
|
+
@log_it.call([false, @verbose, Time.now, '', args].freeze)
|
419
|
+
end
|
420
|
+
|
421
|
+
# -------------------
|
422
|
+
## write a "warn" line with the given message
|
423
|
+
#
|
424
|
+
# @param args the message to log
|
425
|
+
# @return nil
|
426
|
+
def highlight(*args)
|
427
|
+
@log_it.call([false, @verbose, Time.now, '--->', args].freeze)
|
428
|
+
end
|
429
|
+
|
430
|
+
# -------------------
|
431
|
+
## write a "ok" line with the given message
|
432
|
+
#
|
433
|
+
# @param args the message to log
|
434
|
+
# @return nil
|
435
|
+
def ok(*args)
|
436
|
+
@log_it.call([false, @verbose, Time.now, 'OK', args].freeze)
|
437
|
+
end
|
438
|
+
|
439
|
+
# -------------------
|
440
|
+
## write an "err" line with the given message
|
441
|
+
#
|
442
|
+
# @param args the message to log
|
443
|
+
# @return nil
|
444
|
+
def err(*args)
|
445
|
+
@log_it.call([true, @verbose, Time.now, 'ERR', args].freeze)
|
446
|
+
end
|
447
|
+
|
448
|
+
# -------------------
|
449
|
+
## write a "warn" line with the given message
|
450
|
+
#
|
451
|
+
# @param args the message to log
|
452
|
+
# @return nil
|
453
|
+
def warn(*args)
|
454
|
+
@log_it.call([false, @verbose, Time.now, 'WARN', args].freeze)
|
455
|
+
end
|
456
|
+
|
457
|
+
# -------------------
|
458
|
+
## write a "bug" line with the given message
|
459
|
+
#
|
460
|
+
# @param args the message to log
|
461
|
+
# @return nil
|
462
|
+
def bug(*args)
|
463
|
+
@log_it.call([true, @verbose, Time.now, 'BUG', args].freeze)
|
464
|
+
end
|
465
|
+
|
466
|
+
# -------------------
|
467
|
+
## write a "dbg" line with the given message
|
468
|
+
#
|
469
|
+
# @param args the message to log
|
470
|
+
# @return nil
|
471
|
+
def dbg(*args)
|
472
|
+
@log_it.call([false, @verbose, Time.now, 'DBG', args].freeze)
|
473
|
+
end
|
474
|
+
|
475
|
+
# -------------------
|
476
|
+
## write a raw line (no prefix or elapsed)
|
477
|
+
#
|
478
|
+
# @param args the message to log
|
479
|
+
# @return nil
|
480
|
+
def raw(*args)
|
481
|
+
@log_it.call([false, @verbose, Time.now, nil, args].freeze)
|
482
|
+
end
|
483
|
+
|
484
|
+
# -------------------
|
485
|
+
## write an output line with the given message
|
486
|
+
#
|
487
|
+
# @param lineno (optional) the current line number for each line printed
|
488
|
+
# @param args the message to write
|
489
|
+
# @return nil
|
490
|
+
def output(lineno, *args)
|
491
|
+
if lineno.nil?
|
492
|
+
new_args = [' ']
|
493
|
+
else
|
494
|
+
new_args = [format('%3d]', lineno)]
|
495
|
+
end
|
496
|
+
new_args += args
|
497
|
+
@log_it.call([false, @verbose, Time.now, ' --', new_args].freeze)
|
498
|
+
end
|
499
|
+
|
500
|
+
# -------------------
|
501
|
+
## write a list of lines using output()
|
502
|
+
#
|
503
|
+
# @param lines the lines to write
|
504
|
+
# @return nil
|
505
|
+
def num_output(lines)
|
506
|
+
lineno = 0
|
507
|
+
lines.each do |line|
|
508
|
+
lineno += 1
|
509
|
+
output(lineno, line)
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
# --------------------
|
514
|
+
## if ok is true, write an OK line, otherwise an ERR line.
|
515
|
+
#
|
516
|
+
# @param ok condition indicating ok or err
|
517
|
+
# @param args the message to log
|
518
|
+
# @return nil
|
519
|
+
def check(ok, *args)
|
520
|
+
if ok
|
521
|
+
ok(args)
|
522
|
+
else
|
523
|
+
err(args)
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
# --------------------
|
528
|
+
## log a series of messages. Use ok() or err() as appropriate.
|
529
|
+
#
|
530
|
+
# @param ok the check state
|
531
|
+
# @param title the line indicating what the check is about
|
532
|
+
# @param lines individual list of lines to print
|
533
|
+
# @return nil
|
534
|
+
def check_all(ok, title, lines)
|
535
|
+
check(ok, "#{title}: #{ok}")
|
536
|
+
lines.each do |line|
|
537
|
+
check(ok, " - #{line}")
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
# -------------------
|
542
|
+
## add an item to write a 'line' message and a json object to the log
|
543
|
+
#
|
544
|
+
# @param j_data the json object to write
|
545
|
+
# @param args the message to write
|
546
|
+
# @return nil
|
547
|
+
def json(j_data, *args)
|
548
|
+
now = Time.now
|
549
|
+
@log_it.call([false, @verbose, now, ' ', args].freeze)
|
550
|
+
|
551
|
+
j_data = JSON.parse(j_data) if j_data.is_a?(String)
|
552
|
+
JSON.pretty_generate(j_data).split("\n").each do |line|
|
553
|
+
@log_it.call([false, @verbose, now, ' >', [line]].freeze)
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
# -------------------
|
558
|
+
## add an item to write a 'line' message and a data buffer to the log in hex
|
559
|
+
#
|
560
|
+
# @param data the data buffer to write; can be a string or a bytes array
|
561
|
+
# @param args the message to write
|
562
|
+
# @return nil
|
563
|
+
def hex(data, *args)
|
564
|
+
now = Time.now
|
565
|
+
@log_it.call([false, @verbose, now, ' ', args].freeze)
|
566
|
+
line = format('%3d 0x%02X:', 0, 0)
|
567
|
+
data = data.bytes.to_a if data.is_a?(String)
|
568
|
+
|
569
|
+
# data.each_char
|
570
|
+
col = 0
|
571
|
+
data.each_with_index do |ch, i|
|
572
|
+
if col >= 16
|
573
|
+
@log_it.call([false, @verbose, now, '', [' ', line]].freeze)
|
574
|
+
col = 0
|
575
|
+
line = format('%3d 0x%02X:', i, i)
|
576
|
+
end
|
577
|
+
|
578
|
+
line += format(' %02X', ch)
|
579
|
+
col += 1
|
580
|
+
line += ' ' if col == 8
|
581
|
+
end
|
582
|
+
|
583
|
+
# print if there's something left over
|
584
|
+
@log_it.call([false, @verbose, now, ' ', [' ', line]].freeze)
|
585
|
+
end
|
586
|
+
|
587
|
+
# --------------------
|
588
|
+
## write a dot to stdout
|
589
|
+
#
|
590
|
+
# @return nil
|
591
|
+
def dot
|
592
|
+
@log_it.call([false, @verbose, Time.now, '.', [nil]].freeze)
|
593
|
+
end
|
594
|
+
|
595
|
+
# === (some) compatibility with python logger
|
596
|
+
|
597
|
+
# -------------------
|
598
|
+
## write a "debug" line with the given message
|
599
|
+
#
|
600
|
+
# @param args the message to log
|
601
|
+
# @return nil
|
602
|
+
def debug(*args)
|
603
|
+
@log_it.call([false, @verbose, Time.now, 'DBG', args].freeze)
|
604
|
+
end
|
605
|
+
|
606
|
+
# --------------------
|
607
|
+
## write a line with the given message
|
608
|
+
#
|
609
|
+
# @param args the message to log
|
610
|
+
# @return nil
|
611
|
+
def info(*args)
|
612
|
+
@log_it.call([false, @verbose, Time.now, '', args].freeze)
|
613
|
+
end
|
614
|
+
|
615
|
+
# -------------------
|
616
|
+
## write a "warn" line with the given message
|
617
|
+
#
|
618
|
+
# @param args the message to log
|
619
|
+
# @return nil
|
620
|
+
def warning(*args)
|
621
|
+
@log_it.call([false, @verbose, Time.now, 'WARN', args].freeze)
|
622
|
+
end
|
623
|
+
|
624
|
+
# -------------------
|
625
|
+
## write a "err" line with the given message
|
626
|
+
#
|
627
|
+
# @param args the message to log
|
628
|
+
# @return nil
|
629
|
+
def error(*args)
|
630
|
+
@log_it.call([true, @verbose, Time.now, 'ERR', args].freeze)
|
631
|
+
end
|
632
|
+
|
633
|
+
# -------------------
|
634
|
+
## write an "err" line with the given message
|
635
|
+
#
|
636
|
+
# @param args the message to log
|
637
|
+
# @return nil
|
638
|
+
def critical(*args)
|
639
|
+
@log_it.call([true, @verbose, Time.now, 'CRIT', args].freeze)
|
640
|
+
end
|
641
|
+
|
642
|
+
# --------------------
|
643
|
+
## log an exception
|
644
|
+
#
|
645
|
+
# @param excp the exception to print
|
646
|
+
# @param max_lines the maximum lines to print from the backtrace
|
647
|
+
# @return nil
|
648
|
+
def exception(excp, max_lines: 3)
|
649
|
+
now = Time.now
|
650
|
+
|
651
|
+
@log_it.call([true, @verbose, now, 'EXCP', [excp.message]].freeze)
|
652
|
+
@log_it.call([true, @verbose, now, 'EXCP', ['Backtrace:']].freeze)
|
653
|
+
count = 1
|
654
|
+
excp.backtrace.each do |line|
|
655
|
+
@log_it.call([true, @verbose, now, 'EXCP', [' ', line]].freeze)
|
656
|
+
count += 1
|
657
|
+
# :nocov:
|
658
|
+
# coverage: cannot be done in a UT; minitest adds an unknown number of excp lines
|
659
|
+
break if count > max_lines
|
660
|
+
# :nocov:
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
664
|
+
private
|
665
|
+
|
666
|
+
# === logging functions
|
667
|
+
|
668
|
+
# -------------------
|
669
|
+
## write the given line to stdout
|
670
|
+
#
|
671
|
+
# @return nil
|
672
|
+
def _save
|
673
|
+
# if stdout or file is none/closed then nothing to do
|
674
|
+
# if @fp.nil?: # pragma: no cover
|
675
|
+
# # coverage: can not be replicated
|
676
|
+
# # probably redundant to finish but do it anyway
|
677
|
+
# @finished = true
|
678
|
+
# return
|
679
|
+
|
680
|
+
count = @queue.size
|
681
|
+
while count.positive?
|
682
|
+
# in some closing/race conditions, the file may be closed in the middle of a loop
|
683
|
+
# note this can be applied to stdout as well.
|
684
|
+
# :nocov:
|
685
|
+
# coverage: cannot be done in a UT
|
686
|
+
break if @fp.closed?
|
687
|
+
# :nocov:
|
688
|
+
|
689
|
+
# get the next tuple: (always_print, verbose, dts, prefix, args)
|
690
|
+
tuple = @queue.pop
|
691
|
+
always_print = tuple[0]
|
692
|
+
verbose = tuple[1]
|
693
|
+
dts = tuple[2]
|
694
|
+
prefix = tuple[3]
|
695
|
+
args = tuple[4]
|
696
|
+
count -= 1
|
697
|
+
|
698
|
+
# uncomment to debug
|
699
|
+
# puts("#{always_print} #{verbose} '#{prefix}' #{dts} '#{args}'")
|
700
|
+
|
701
|
+
# not verbose and ok not to print
|
702
|
+
next unless verbose || always_print
|
703
|
+
|
704
|
+
if args[0].nil? && prefix == '.'
|
705
|
+
# dots used to log waiting periods, so okay to call fn
|
706
|
+
_handle_dots
|
707
|
+
next
|
708
|
+
end
|
709
|
+
|
710
|
+
# at this point, not a dot
|
711
|
+
|
712
|
+
# last call was a dot, so reset and print a newline ready for the new log line
|
713
|
+
if @dots != 0
|
714
|
+
@dots = 0
|
715
|
+
@fp.write("\n")
|
716
|
+
@runner_cfg.copy_from(@backup_cfg)
|
717
|
+
end
|
718
|
+
|
719
|
+
# print the full DTS requested by the user
|
720
|
+
if args[0].nil? && prefix.nil?
|
721
|
+
# rare request, so okay to call fn
|
722
|
+
_handle_full_dts(dts)
|
723
|
+
next
|
724
|
+
end
|
725
|
+
|
726
|
+
# print with no prefix or elapsed time
|
727
|
+
if @log_format == LogFormat::NONE
|
728
|
+
line = args.join(' ')
|
729
|
+
@fp.write(line)
|
730
|
+
@fp.write("\n")
|
731
|
+
next
|
732
|
+
end
|
733
|
+
|
734
|
+
# print with the prefix, but no elapsed time
|
735
|
+
if @log_format == LogFormat::PREFIX
|
736
|
+
line = args.join(' ')
|
737
|
+
if prefix.nil?
|
738
|
+
msg = line # raw line
|
739
|
+
else
|
740
|
+
msg = format('%-4s %s', prefix, line)
|
741
|
+
end
|
742
|
+
@fp.write(msg)
|
743
|
+
@fp.write("\n")
|
744
|
+
next
|
745
|
+
end
|
746
|
+
|
747
|
+
# at this point, mode is LogFormat.ELAPSED
|
748
|
+
|
749
|
+
# approximately once an hour, restart the time period
|
750
|
+
elapsed = Time.at(dts - @start_time)
|
751
|
+
if elapsed.to_f > 3600.0
|
752
|
+
# rare, so okay to call fn
|
753
|
+
# display the time at the moment the log line was saved
|
754
|
+
_handle_full_dts(dts)
|
755
|
+
|
756
|
+
# recalc the elapsed time, should be 0
|
757
|
+
# add the small value for round-off issues
|
758
|
+
elapsed = Time.at(dts - @start_time) # + 0.0001)
|
759
|
+
end
|
760
|
+
|
761
|
+
# print prefix and elapsed time
|
762
|
+
line = args.join(' ')
|
763
|
+
|
764
|
+
# log the line
|
765
|
+
if prefix.nil?
|
766
|
+
msg = line
|
767
|
+
else
|
768
|
+
t_str = _get_elapsed_str(elapsed)
|
769
|
+
msg = format('%s %-4s %s', t_str, prefix, line)
|
770
|
+
end
|
771
|
+
|
772
|
+
# assume @fp is not closed
|
773
|
+
@fp.write(msg)
|
774
|
+
@fp.write("\n")
|
775
|
+
end
|
776
|
+
|
777
|
+
# uncomment to debug
|
778
|
+
# @fp.close
|
779
|
+
|
780
|
+
# flush lines to stdout/file; protect with except in case
|
781
|
+
begin
|
782
|
+
@fp.flush
|
783
|
+
rescue IOError
|
784
|
+
# coverage: rare case: if stdout/file is closed this will throw an exception
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
# --------------------
|
789
|
+
## If past max_dots, print a newline. Then print a dot.
|
790
|
+
#
|
791
|
+
# @return none
|
792
|
+
def _handle_dots
|
793
|
+
if @dots.zero?
|
794
|
+
# save delay and count
|
795
|
+
@backup_cfg.copy_from(@runner_cfg)
|
796
|
+
@runner_cfg.loop_delay = 0.100
|
797
|
+
@runner_cfg.max_entries = 1
|
798
|
+
@runner_cfg.max_count = 1
|
799
|
+
end
|
800
|
+
|
801
|
+
if @dots >= @max_dots
|
802
|
+
@fp.write("\n")
|
803
|
+
@dots = 0
|
804
|
+
end
|
805
|
+
|
806
|
+
@fp.write('.')
|
807
|
+
@dots += 1
|
808
|
+
end
|
809
|
+
|
810
|
+
# --------------------
|
811
|
+
## print full DTS stamp
|
812
|
+
#
|
813
|
+
# @param dts the dts of the current log line
|
814
|
+
# @return nil
|
815
|
+
def _handle_full_dts(dts)
|
816
|
+
# restart the timer; user wants the full DTS and elapsed is since that absolute time
|
817
|
+
@start_time = dts
|
818
|
+
|
819
|
+
full_dts = format('%-4s %s', 'DTS', dts.strftime('%4Y/%2m/%2d %2H:%2M:%2S.%3N'))
|
820
|
+
full_dts = format('%9s %s', '', full_dts) if @log_format == LogFormat::ELAPSED
|
821
|
+
@fp.write(full_dts)
|
822
|
+
@fp.write("\n")
|
823
|
+
end
|
824
|
+
|
825
|
+
# --------------------
|
826
|
+
## generate the string of the given elapsed time
|
827
|
+
#
|
828
|
+
# @param elapsed the elapsed time to format
|
829
|
+
# @return the string ("MM.SS.nnn")
|
830
|
+
def _get_elapsed_str(elapsed)
|
831
|
+
elapsed = Time.at(elapsed) if elapsed.is_a?(Float)
|
832
|
+
elapsed.strftime('%2M:%2S.%3N')
|
833
|
+
end
|
834
|
+
|
835
|
+
# --------------------
|
836
|
+
## the thread runner
|
837
|
+
# wakes periodically to check if the queue has max_entries or more in it
|
838
|
+
# if so, the lines are written to the file
|
839
|
+
# if not, it sleeps
|
840
|
+
#
|
841
|
+
# @return nil
|
842
|
+
def _runner
|
843
|
+
count = 0
|
844
|
+
until @finished
|
845
|
+
# sleep until:
|
846
|
+
# - there are enough entries in the queue
|
847
|
+
# - the max delay is reached
|
848
|
+
if @queue.size < @runner_cfg.max_entries && count < @runner_cfg.max_count
|
849
|
+
count += 1
|
850
|
+
sleep(@runner_cfg.loop_delay)
|
851
|
+
next
|
852
|
+
end
|
853
|
+
|
854
|
+
# write out all the current entries
|
855
|
+
count = 0
|
856
|
+
_save
|
857
|
+
end
|
858
|
+
rescue Interrupt # handle ctrl-c
|
859
|
+
# nothing to do
|
860
|
+
ensure
|
861
|
+
# save any remaining entries
|
862
|
+
_save
|
863
|
+
|
864
|
+
# close the file if necessary
|
865
|
+
if @path && !@fp.nil?
|
866
|
+
@fp.close
|
867
|
+
@fp = nil
|
868
|
+
end
|
869
|
+
end
|
870
|
+
end
|
data/lib/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rb_falcon_logger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- J. Arrizza
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-06-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: fast logger with multiple modes and formats
|
14
|
+
email: cppgent0@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- LICENSE.txt
|
20
|
+
- README.md
|
21
|
+
- lib/gem_source/logger.rb
|
22
|
+
- lib/rb_falcon_logger.rb
|
23
|
+
- lib/version.rb
|
24
|
+
homepage: https://rubygems.org/gems/rb-falcon-logger
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
metadata:
|
28
|
+
homepage_uri: https://arrizza.com/rb-falcon-logger
|
29
|
+
source_code_uri: https://bitbucket.org/arrizza-public/rb-falcon-logger/src/master
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 3.2.0
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubygems_version: 3.4.20
|
46
|
+
signing_key:
|
47
|
+
specification_version: 4
|
48
|
+
summary: fast logger, several modes and formats
|
49
|
+
test_files: []
|