moon-logfmt 1.0.3 → 1.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 +4 -4
- data/lib/moon-logfmt/formatter.rb +35 -6
- data/lib/moon-logfmt/logfmt.rb +0 -34
- data/lib/moon-logfmt/logger.rb +66 -17
- data/lib/moon-logfmt/severity.rb +19 -0
- data/lib/moon-logfmt/stdlib_loggable.rb +13 -29
- data/lib/moon-logfmt/utils.rb +53 -0
- data/lib/moon-logfmt/version.rb +1 -1
- data/spec/logfmt_spec.rb +7 -0
- data/spec/logger_spec.rb +65 -24
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad3d92684b23cd251495e9723dddbcd87db16ae8
|
4
|
+
data.tar.gz: e393c13c1f7c40e8d64313cf48d2826f93ae82a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce0188e6c9f29a7a43f33648d460b2b66bd088b0f2bd14afb1eb9f6c24af87582f92925f657e06e72fb5a9679ef74e09d681cf7b2967e0eb795af51f921aad94
|
7
|
+
data.tar.gz: f81eca8be731925137a3777842e74d75ad727dfe0b95f339ca2e5f3a13e952a5ccf747a3376fbd4ab293eecdc2e4abe3f0cb9598426a1d488fe52cdda7ecb79c
|
@@ -1,10 +1,39 @@
|
|
1
1
|
module Moon
|
2
2
|
module Logfmt
|
3
|
-
#
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
# Identity Formatter, this was created to interact with the stdlib
|
4
|
+
# Logger::Formatter
|
5
|
+
class Formatter
|
6
|
+
# @return [String] message
|
7
|
+
def call(severity, time, progname, msg)
|
8
|
+
msg
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns the default instance of the formatter
|
12
|
+
#
|
13
|
+
# @return [Formatter]
|
14
|
+
def self.default
|
15
|
+
@default ||= new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Logfmt's actual formatter, this takes a key and a value and produces
|
20
|
+
# a string
|
21
|
+
class KeyValueFormatter
|
22
|
+
# Default KEY=VALUE formatter
|
23
|
+
#
|
24
|
+
# @param [String] key
|
25
|
+
# @param [String] value
|
26
|
+
# @return [String]
|
27
|
+
def call(key, value)
|
28
|
+
"#{key}=#{value}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the default instance of the key value formatter
|
32
|
+
#
|
33
|
+
# @return [KeyValueFormatter]
|
34
|
+
def self.default
|
35
|
+
@default ||= new
|
36
|
+
end
|
37
|
+
end
|
9
38
|
end
|
10
39
|
end
|
data/lib/moon-logfmt/logfmt.rb
CHANGED
@@ -1,36 +1,2 @@
|
|
1
1
|
require 'moon-logfmt/logger'
|
2
2
|
require 'moon-logfmt/null_logger'
|
3
|
-
|
4
|
-
module Moon
|
5
|
-
# Implementation of logfmt for Moon
|
6
|
-
module Logfmt
|
7
|
-
# Regular expression used for checking strings that may need escaping.
|
8
|
-
# This regular expression will validate true if the string doesn't need
|
9
|
-
# escaping.
|
10
|
-
UNESCAPED_STRING = /\A[\w\.\-\+\%\_\,\:\;\/]*\z/i
|
11
|
-
|
12
|
-
# Escapes the context values and yields the result.
|
13
|
-
#
|
14
|
-
# @param [Hash<[String, Symbol], String>] data
|
15
|
-
# @yieldparam [String] key
|
16
|
-
# @yieldparam [String] value
|
17
|
-
def self.escape_context_data(data)
|
18
|
-
return to_enum :escape_context_data, data unless block_given?
|
19
|
-
data.each_pair do |key, value|
|
20
|
-
case value
|
21
|
-
when Array
|
22
|
-
value = value.join(',')
|
23
|
-
else
|
24
|
-
value = value.to_s
|
25
|
-
end
|
26
|
-
value = value.dump unless value =~ UNESCAPED_STRING
|
27
|
-
yield key.to_s, value
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# (see Moon::Logfmt::Logger#initialize)
|
32
|
-
def self.new(*args, &block)
|
33
|
-
Moon::Logfmt::Logger.new(*args, &block)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/lib/moon-logfmt/logger.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'moon-logfmt/stdlib_loggable'
|
2
2
|
require 'moon-logfmt/formatter'
|
3
|
+
require 'moon-logfmt/utils'
|
3
4
|
|
4
5
|
module Moon
|
5
6
|
module Logfmt
|
@@ -8,6 +9,11 @@ module Moon
|
|
8
9
|
# #new will copy the current logger and append its context data
|
9
10
|
class Logger
|
10
11
|
include StdlibLoggable
|
12
|
+
include Severity
|
13
|
+
|
14
|
+
# The default datetime string format
|
15
|
+
# @return [String]
|
16
|
+
DEFAULT_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S%Z'.freeze
|
11
17
|
|
12
18
|
# The underlaying IO to write to, the default is STDOUT
|
13
19
|
# @return [IO, #puts]
|
@@ -15,6 +21,10 @@ module Moon
|
|
15
21
|
|
16
22
|
# A function which takes a key and value string and produces a string
|
17
23
|
# @return [Proc]
|
24
|
+
attr_accessor :key_value_formatter
|
25
|
+
|
26
|
+
# A function which takes the final context string and formats it
|
27
|
+
# @return [Proc]
|
18
28
|
attr_accessor :formatter
|
19
29
|
|
20
30
|
# Whether to prepend timestamps to the logs
|
@@ -30,52 +40,91 @@ module Moon
|
|
30
40
|
# @param [Hash<[String, Symbol], String>] data
|
31
41
|
def initialize(data = {})
|
32
42
|
@io = STDOUT
|
33
|
-
@formatter =
|
43
|
+
@formatter = Formatter.default
|
44
|
+
@key_value_formatter = KeyValueFormatter.default
|
34
45
|
@context = data
|
35
46
|
@timestamp = true
|
47
|
+
@level = Moon::Logfmt::Severity::DEBUG
|
48
|
+
@datetime_format = DEFAULT_DATETIME_FORMAT
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :level
|
52
|
+
|
53
|
+
# @param [Symbol]
|
54
|
+
def level=(lvl)
|
55
|
+
@level = Moon::Logfmt.determine_loglevel_from_object(lvl)
|
36
56
|
end
|
37
57
|
|
38
58
|
# @param [Logfmt::Logger] org
|
39
59
|
# @return [self]
|
40
60
|
def initialize_copy(org)
|
41
61
|
@io = org.io
|
62
|
+
@level = org.level
|
42
63
|
@timestamp = org.timestamp
|
43
64
|
@context = org.context.dup
|
44
65
|
@formatter = org.formatter
|
66
|
+
@key_value_formatter = org.key_value_formatter
|
45
67
|
self
|
46
68
|
end
|
47
69
|
|
70
|
+
# @param [Integer] severity
|
71
|
+
# @return [Symbol]
|
72
|
+
private def severity_to_symbol(severity)
|
73
|
+
case severity
|
74
|
+
when DEBUG then :debug
|
75
|
+
when INFO then :info
|
76
|
+
when WARN then :warn
|
77
|
+
when ERROR then :error
|
78
|
+
when FATAL then :fatal
|
79
|
+
when UNKNOWN then :unknown
|
80
|
+
else
|
81
|
+
severity.to_s
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Adds timestamp information to the provided data
|
86
|
+
#
|
87
|
+
# @param [Hash<Symbol, Object>] data to add timestamp to
|
88
|
+
# @return [Hash] data given
|
89
|
+
private def timestamp_context(data)
|
90
|
+
data.tap { |d| d[:now] = Time.now.strftime(@datetime_format) }
|
91
|
+
end
|
92
|
+
|
48
93
|
# Formats the provided context data
|
49
94
|
#
|
50
95
|
# @param [Hash<[String, Symbol], String>] data
|
51
96
|
# @return [String]
|
52
|
-
private def format_context(
|
97
|
+
private def format_context(severity, time, progname, ctx)
|
98
|
+
data = {}
|
99
|
+
data[:level] = severity_to_symbol(severity) if severity
|
100
|
+
timestamp_context(data) if @timestamp
|
101
|
+
data[:progname] = progname if progname
|
102
|
+
data.merge!(ctx)
|
53
103
|
str = []
|
54
104
|
Logfmt.escape_context_data data do |key, value|
|
55
|
-
str << @
|
105
|
+
str << @key_value_formatter.call(key, value)
|
56
106
|
end
|
57
|
-
str.join(' ')
|
107
|
+
@formatter.call(severity, time, progname, str.join(' '))
|
58
108
|
end
|
59
109
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
110
|
+
protected def write_to_logdev(str)
|
111
|
+
@io.puts str
|
112
|
+
end
|
113
|
+
|
114
|
+
# Writes a new context line to the logdev
|
115
|
+
# @param [Integer] severity
|
116
|
+
# @param [Time] time
|
117
|
+
# @param [String] progname
|
118
|
+
# @param [Hash] ctx
|
119
|
+
protected def write_context(severity, time, progname, ctx)
|
120
|
+
write_to_logdev format_context(severity, time, progname, context.merge(ctx))
|
70
121
|
end
|
71
122
|
|
72
123
|
# Writes a new log line
|
73
124
|
#
|
74
125
|
# @param [Hash<[String, Symbol], String>] data
|
75
126
|
def write(data)
|
76
|
-
|
77
|
-
timestamp_context(pre) if @timestamp
|
78
|
-
@io.puts format_context(pre.merge(context.merge(data)))
|
127
|
+
write_context nil, Time.now, nil, data
|
79
128
|
end
|
80
129
|
|
81
130
|
# Creates a new context by forking the current logger
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Moon
|
2
|
+
module Logfmt
|
3
|
+
# Logging severity.
|
4
|
+
module Severity
|
5
|
+
# Low-level information, mostly for developers.
|
6
|
+
DEBUG = 0
|
7
|
+
# Generic (useful) information about system operation.
|
8
|
+
INFO = 1
|
9
|
+
# A warning.
|
10
|
+
WARN = 2
|
11
|
+
# A handleable error condition.
|
12
|
+
ERROR = 3
|
13
|
+
# An unhandleable error that results in a program crash.
|
14
|
+
FATAL = 4
|
15
|
+
# An unknown message that should always be logged.
|
16
|
+
UNKNOWN = 5
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,54 +1,38 @@
|
|
1
|
+
require 'moon-logfmt/severity'
|
2
|
+
|
1
3
|
module Moon
|
2
4
|
module Logfmt
|
3
|
-
# Logging severity.
|
4
|
-
module Severity
|
5
|
-
# Low-level information, mostly for developers.
|
6
|
-
DEBUG = 0
|
7
|
-
# Generic (useful) information about system operation.
|
8
|
-
INFO = 1
|
9
|
-
# A warning.
|
10
|
-
WARN = 2
|
11
|
-
# A handleable error condition.
|
12
|
-
ERROR = 3
|
13
|
-
# An unhandleable error that results in a program crash.
|
14
|
-
FATAL = 4
|
15
|
-
# An unknown message that should always be logged.
|
16
|
-
UNKNOWN = 5
|
17
|
-
end
|
18
|
-
|
19
5
|
# Interface for the stdlib Logger class
|
20
6
|
module StdlibLoggable
|
21
7
|
include Severity
|
22
8
|
|
23
9
|
# @!group std Logger interface
|
10
|
+
|
11
|
+
# Adds a new logger message
|
12
|
+
#
|
24
13
|
# @param [Severity] severity
|
25
14
|
# @param [String, nil] message
|
26
15
|
# @param [String, nil] progname
|
27
16
|
# @yieldreturn [String] message
|
28
17
|
def add(severity, message = nil, progname = nil, &block)
|
18
|
+
return if severity < @level
|
29
19
|
message = message || (block && block.call)
|
30
20
|
msg = message || progname
|
31
21
|
data = {}
|
32
|
-
|
33
|
-
data
|
34
|
-
when DEBUG then :debug
|
35
|
-
when ERROR then :error
|
36
|
-
when FATAL then :fatal
|
37
|
-
when INFO then :msg
|
38
|
-
when UNKNOWN then :msg
|
39
|
-
when WARN then :warn
|
40
|
-
end] = msg
|
41
|
-
write data
|
22
|
+
msg.is_a?(Hash) ? data.merge!(msg) : data.store(:msg, msg)
|
23
|
+
write_context(severity, Time.now, progname, data)
|
42
24
|
end
|
43
25
|
alias :log :add
|
44
26
|
|
45
27
|
# Logs a message
|
46
28
|
#
|
29
|
+
# @overload info(data)
|
30
|
+
# @param [Hash] data - data to log
|
47
31
|
# @overload info(message)
|
48
|
-
# @param [String] message
|
32
|
+
# @param [String] message - message to log
|
49
33
|
# @overload info(progname, &block)
|
50
|
-
# @param [String] progname
|
51
|
-
# @yieldreturn [String] message
|
34
|
+
# @param [String] progname - program name
|
35
|
+
# @yieldreturn [String] message - message to log
|
52
36
|
def info(progname = nil, &block)
|
53
37
|
add(INFO, nil, progname, &block)
|
54
38
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'moon-logfmt/severity'
|
2
|
+
|
3
|
+
module Moon
|
4
|
+
# Implementation of logfmt for Moon
|
5
|
+
module Logfmt
|
6
|
+
# Regular expression used for checking strings that may need escaping.
|
7
|
+
# This regular expression will validate true if the string doesn't need
|
8
|
+
# escaping.
|
9
|
+
UNESCAPED_STRING = /\A[\w\.\-\+\%\_\,\:\;\/]*\z/i
|
10
|
+
|
11
|
+
# Escapes the context values and yields the result.
|
12
|
+
#
|
13
|
+
# @param [Hash<[String, Symbol], String>] data
|
14
|
+
# @yieldparam [String] key
|
15
|
+
# @yieldparam [String] value
|
16
|
+
def self.escape_context_data(data)
|
17
|
+
return to_enum :escape_context_data, data unless block_given?
|
18
|
+
data.each_pair do |key, value|
|
19
|
+
case value
|
20
|
+
when Array
|
21
|
+
value = value.join(',')
|
22
|
+
else
|
23
|
+
value = value.to_s
|
24
|
+
end
|
25
|
+
value = value.dump unless value =~ UNESCAPED_STRING
|
26
|
+
yield key.to_s, value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Determines what the loglevel should be from the given object
|
31
|
+
#
|
32
|
+
# @param [Object] object
|
33
|
+
# @return [Integer] loglevel
|
34
|
+
def self.determine_loglevel_from_object(object)
|
35
|
+
return object if object.is_a?(Integer)
|
36
|
+
case object.to_s.upcase
|
37
|
+
when 'DEBUG' then Moon::Logfmt::Severity::DEBUG
|
38
|
+
when 'INFO' then Moon::Logfmt::Severity::INFO
|
39
|
+
when 'WARN' then Moon::Logfmt::Severity::WARN
|
40
|
+
when 'ERROR' then Moon::Logfmt::Severity::ERROR
|
41
|
+
when 'FATAL' then Moon::Logfmt::Severity::FATAL
|
42
|
+
when 'UNKNOWN' then Moon::Logfmt::Severity::UNKNOWN
|
43
|
+
else
|
44
|
+
raise ArgumentError, "unknown log level #{object}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# (see Moon::Logfmt::Logger#initialize)
|
49
|
+
def self.new(*args, &block)
|
50
|
+
Moon::Logfmt::Logger.new(*args, &block)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/moon-logfmt/version.rb
CHANGED
data/spec/logfmt_spec.rb
CHANGED
@@ -2,6 +2,13 @@ require 'spec_helper'
|
|
2
2
|
require 'moon-logfmt/logfmt'
|
3
3
|
|
4
4
|
describe Moon::Logfmt do
|
5
|
+
context '.new' do
|
6
|
+
it 'creates a new Logger instance' do
|
7
|
+
logger = described_class.new
|
8
|
+
expect(logger).to be_instance_of(Moon::Logfmt::Logger)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
5
12
|
context '.escape_context_data' do
|
6
13
|
it 'formats a Hash to a String' do
|
7
14
|
actual = described_class.escape_context_data(msg: 'Hello World', nums: [1, 2, 3]).to_a
|
data/spec/logger_spec.rb
CHANGED
@@ -32,40 +32,81 @@ describe Moon::Logfmt::Logger do
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
context '
|
36
|
-
|
37
|
-
|
35
|
+
context 'std logger interface' do
|
36
|
+
context '#level=' do
|
37
|
+
it 'will accept symbols' do
|
38
|
+
null_logger.level = :debug
|
39
|
+
expect(null_logger.level).to eq(Moon::Logfmt::Severity::DEBUG)
|
40
|
+
|
41
|
+
null_logger.level = :info
|
42
|
+
expect(null_logger.level).to eq(Moon::Logfmt::Severity::INFO)
|
43
|
+
|
44
|
+
null_logger.level = :warn
|
45
|
+
expect(null_logger.level).to eq(Moon::Logfmt::Severity::WARN)
|
46
|
+
|
47
|
+
null_logger.level = :error
|
48
|
+
expect(null_logger.level).to eq(Moon::Logfmt::Severity::ERROR)
|
49
|
+
|
50
|
+
null_logger.level = :fatal
|
51
|
+
expect(null_logger.level).to eq(Moon::Logfmt::Severity::FATAL)
|
52
|
+
|
53
|
+
null_logger.level = :unknown
|
54
|
+
expect(null_logger.level).to eq(Moon::Logfmt::Severity::UNKNOWN)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'will accept strings' do
|
58
|
+
null_logger.level = 'debug'
|
59
|
+
expect(null_logger.level).to eq(Moon::Logfmt::Severity::DEBUG)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'will accept integers' do
|
63
|
+
null_logger.level = 0
|
64
|
+
expect(null_logger.level).to eq(Moon::Logfmt::Severity::DEBUG)
|
65
|
+
|
66
|
+
null_logger.level = 5
|
67
|
+
expect(null_logger.level).to eq(Moon::Logfmt::Severity::UNKNOWN)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'will fail given an invalid level' do
|
71
|
+
expect { null_logger.level = :something }.to raise_error(ArgumentError)
|
72
|
+
end
|
38
73
|
end
|
39
|
-
end
|
40
74
|
|
41
|
-
|
42
|
-
|
43
|
-
|
75
|
+
context '#info' do
|
76
|
+
it 'writes a basic message' do
|
77
|
+
null_logger.info 'Test Test Test'
|
78
|
+
end
|
44
79
|
end
|
45
|
-
end
|
46
80
|
|
47
|
-
|
48
|
-
|
49
|
-
|
81
|
+
context '#debug' do
|
82
|
+
it 'writes a debug message' do
|
83
|
+
null_logger.debug { 'Test Test Test' }
|
84
|
+
end
|
50
85
|
end
|
51
|
-
end
|
52
86
|
|
53
|
-
|
54
|
-
|
55
|
-
|
87
|
+
context '#warn' do
|
88
|
+
it 'writes a warning message' do
|
89
|
+
null_logger.warn { 'Test Test Test' }
|
90
|
+
end
|
56
91
|
end
|
57
|
-
end
|
58
92
|
|
59
|
-
|
60
|
-
|
61
|
-
|
93
|
+
context '#error' do
|
94
|
+
it 'writes a warning message' do
|
95
|
+
null_logger.error('testapp') { 'Test Test Test' }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context '#fatal' do
|
100
|
+
it 'writes a fatal message' do
|
101
|
+
null_logger.fatal 'AND I DIED'
|
102
|
+
end
|
62
103
|
end
|
63
|
-
end
|
64
104
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
105
|
+
context '#warn' do
|
106
|
+
it 'writes a unknown message' do
|
107
|
+
# more like a spooky message
|
108
|
+
null_logger.unknown { 'Spoooooky' }
|
109
|
+
end
|
69
110
|
end
|
70
111
|
end
|
71
112
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moon-logfmt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blaž Hrastnik
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-04-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: moon-null_io
|
@@ -142,7 +142,9 @@ files:
|
|
142
142
|
- lib/moon-logfmt/logger.rb
|
143
143
|
- lib/moon-logfmt/null_logger.rb
|
144
144
|
- lib/moon-logfmt/pkg.yml
|
145
|
+
- lib/moon-logfmt/severity.rb
|
145
146
|
- lib/moon-logfmt/stdlib_loggable.rb
|
147
|
+
- lib/moon-logfmt/utils.rb
|
146
148
|
- lib/moon-logfmt/version.rb
|
147
149
|
- spec/logfmt_spec.rb
|
148
150
|
- spec/logger_spec.rb
|