vx-lib-logger 0.1.1 → 0.2.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/vx/lib/logger.rb +7 -4
- data/lib/vx/lib/logger/instance.rb +43 -11
- data/lib/vx/lib/logger/journal_formatter.rb +31 -0
- data/lib/vx/lib/logger/logstash.rb +87 -0
- data/lib/vx/lib/logger/sanitizer.rb +20 -0
- data/lib/vx/lib/logger/{json_formatter.rb → stdout_formatter.rb} +3 -3
- data/lib/vx/lib/logger/version.rb +1 -1
- data/spec/lib/instance_spec.rb +86 -72
- data/spec/lib/logstash_spec.rb +42 -0
- data/spec/spec_helper.rb +22 -0
- metadata +8 -5
- data/lib/vx/lib/logger/raw_formatter.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3cd5b9c66ac3665ca6ec8c71115a1a0c92a75a49
|
4
|
+
data.tar.gz: 580fad2cf11354a4f0712482cf3a2074b04b2578
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdfabb6e1f5ea36ef83d26b3af50c44004174937bbd23a474c26cfb7b9f9d3c4422fe51d6182f7170e86d4803ae3f03e72719a1e545bd29bd6816e419b8f741a
|
7
|
+
data.tar.gz: f9610c3f29159002a469e8ab2edd16ca5fed2326bea24ed7f28cfdd52c579ed088fd5f8731c709b5ea5d46c1eb07266f1c2f1b283ee98b6a93876c66a8169138
|
data/lib/vx/lib/logger.rb
CHANGED
@@ -5,17 +5,20 @@ module Vx ; module Lib
|
|
5
5
|
module Logger
|
6
6
|
|
7
7
|
autoload :Instance, File.expand_path("../logger/instance", __FILE__)
|
8
|
-
autoload :
|
9
|
-
autoload :
|
8
|
+
autoload :StdoutFormatter, File.expand_path("../logger/stdout_formatter", __FILE__)
|
9
|
+
autoload :JournalFormatter, File.expand_path("../logger/journal_formatter", __FILE__)
|
10
|
+
autoload :Logstash, File.expand_path("../logger/logstash", __FILE__)
|
11
|
+
autoload :Sanitizer, File.expand_path("../logger/sanitizer", __FILE__)
|
10
12
|
|
11
13
|
module Rack
|
12
14
|
autoload :HandleExceptions, File.expand_path("../logger/rack/handle_exceptions", __FILE__)
|
13
15
|
end
|
14
16
|
|
15
|
-
@@
|
17
|
+
@@logstash = Logstash.new
|
18
|
+
@@default = Instance.new(STDOUT, logstash: @@logstash)
|
16
19
|
|
17
20
|
def self.get(io = nil, options = {})
|
18
|
-
Instance.new(io || STDOUT, options)
|
21
|
+
Instance.new(io || STDOUT, options.merge(logstash: @@logstash))
|
19
22
|
end
|
20
23
|
|
21
24
|
def self.default
|
@@ -1,16 +1,33 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'thread'
|
3
|
+
require 'socket'
|
3
4
|
|
4
5
|
module Vx ; module Lib ; module Logger
|
5
6
|
|
6
7
|
class Instance
|
7
8
|
|
8
|
-
attr_reader :params, :logger
|
9
|
+
attr_reader :params, :logger, :logstash
|
9
10
|
|
10
11
|
def initialize(io, params = {})
|
11
|
-
@
|
12
|
+
@logstash = params.delete(:logstash)
|
13
|
+
@params = params
|
14
|
+
|
15
|
+
@progname = @params.delete(:progname)
|
16
|
+
|
17
|
+
@progname ||= begin
|
18
|
+
pname = $PROGRAM_NAME
|
19
|
+
pname && File.basename(pname)
|
20
|
+
end
|
21
|
+
|
22
|
+
@formatter = ->(_,_,_,m) { m }
|
23
|
+
|
12
24
|
@logger = ::Logger.new(io, 7, 50_000_000)
|
13
|
-
@logger.formatter =
|
25
|
+
@logger.formatter = @formatter
|
26
|
+
@logger.progname = @progname
|
27
|
+
|
28
|
+
@logstash_logger = ::Logger.new(logstash)
|
29
|
+
@logstash_logger.formatter = @formatter
|
30
|
+
@logstash_logger.progname = @progname
|
14
31
|
end
|
15
32
|
|
16
33
|
[:fatal, :warn, :debug, :error, :info].each do |m|
|
@@ -32,7 +49,7 @@ module Vx ; module Lib ; module Logger
|
|
32
49
|
end
|
33
50
|
|
34
51
|
def progname=(new_val)
|
35
|
-
|
52
|
+
@progname = new_val
|
36
53
|
end
|
37
54
|
|
38
55
|
def handle(message, options = {})
|
@@ -64,29 +81,44 @@ module Vx ; module Lib ; module Logger
|
|
64
81
|
def process_message(level, message, options = {})
|
65
82
|
|
66
83
|
if options[:exception] && options[:exception].is_a?(Exception)
|
67
|
-
ex = options
|
84
|
+
ex = options.delete(:exception)
|
68
85
|
options.merge!(
|
69
|
-
exception: [ex.class.to_s, ex.message],
|
86
|
+
exception: [ex.class.to_s, ex.message].join(" - "),
|
70
87
|
backtrace: (ex.backtrace || []).map(&:to_s).join("\n"),
|
71
88
|
)
|
72
89
|
end
|
73
90
|
|
74
91
|
body = {
|
75
92
|
thread_id: ::Thread.current.object_id,
|
76
|
-
process_id: ::Process.pid,
|
77
93
|
}
|
78
94
|
|
79
95
|
if options && options != {}
|
96
|
+
|
97
|
+
duration = options.delete(:duration)
|
98
|
+
if duration && duration.respond_to?(:to_f)
|
99
|
+
body.merge!(duration: duration.to_f)
|
100
|
+
end
|
101
|
+
|
80
102
|
body.merge!(
|
81
|
-
fields: options
|
103
|
+
fields: Sanitizer.hash(options)
|
82
104
|
)
|
83
105
|
end
|
84
106
|
|
85
|
-
|
107
|
+
|
108
|
+
@logger.public_send level, format_stdout(level, message, body)
|
109
|
+
|
110
|
+
if logstash.enabled?
|
111
|
+
@logstash_logger.public_send level, format_journal(level, message, body)
|
112
|
+
end
|
86
113
|
end
|
87
114
|
|
88
|
-
def
|
89
|
-
|
115
|
+
def format_stdout(level, message, payload)
|
116
|
+
StdoutFormatter.call(level, message, payload)
|
117
|
+
end
|
118
|
+
|
119
|
+
def format_journal(level, message, payload)
|
120
|
+
JournalFormatter.call(level, @progname, message, payload)
|
121
|
+
|
90
122
|
end
|
91
123
|
|
92
124
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'oj'
|
2
|
+
|
3
|
+
module Vx ; module Lib ; module Logger
|
4
|
+
|
5
|
+
module JournalFormatter
|
6
|
+
|
7
|
+
@@exe = $PROGRAM_NAME
|
8
|
+
@@gid = ::Process.gid
|
9
|
+
@@uid = ::Process.uid
|
10
|
+
@@pid = ::Process.pid
|
11
|
+
@@host = ::Socket.gethostname
|
12
|
+
|
13
|
+
def self.call(level, progname, message, payload)
|
14
|
+
m = ::Oj.dump(
|
15
|
+
payload.merge(
|
16
|
+
MESSAGE: message.to_s,
|
17
|
+
SYSLOG_IDENTIFIER: progname,
|
18
|
+
_EXE: @@exe,
|
19
|
+
_GID: @@gid,
|
20
|
+
_UID: @@uid,
|
21
|
+
_PID: @@pid,
|
22
|
+
_HOSTNAME: @@host,
|
23
|
+
level: level,
|
24
|
+
),
|
25
|
+
mode: :compat
|
26
|
+
)
|
27
|
+
m.encode("UTF-8", invalid: :replace, replace: "?") << "\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end ; end ; end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'uri'
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Vx ; module Lib ; module Logger
|
6
|
+
|
7
|
+
class Logstash
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@mutex = Mutex.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def uri
|
14
|
+
@uri ||= begin
|
15
|
+
h = ENV['LOGSTASH_HOST']
|
16
|
+
URI("logstash://#{h}") if h
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def enabled?
|
21
|
+
!!uri
|
22
|
+
end
|
23
|
+
|
24
|
+
def connected?
|
25
|
+
!!@io
|
26
|
+
end
|
27
|
+
|
28
|
+
def close
|
29
|
+
@io && @io.close
|
30
|
+
rescue Exception => e
|
31
|
+
warn "#{self.class} - #{e.class} - #{e.message}"
|
32
|
+
ensure
|
33
|
+
@io = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def write(message)
|
37
|
+
if enabled?
|
38
|
+
@mutex.synchronize do
|
39
|
+
with_connection do
|
40
|
+
@io.write message
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def flush
|
47
|
+
@io && @io.flush
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def host
|
53
|
+
uri.host
|
54
|
+
end
|
55
|
+
|
56
|
+
def port
|
57
|
+
@port ||= uri.port || 514
|
58
|
+
end
|
59
|
+
|
60
|
+
def warn(msg)
|
61
|
+
$stderr.puts msg
|
62
|
+
end
|
63
|
+
|
64
|
+
def with_connection(&block)
|
65
|
+
connect unless connected?
|
66
|
+
yield
|
67
|
+
rescue Exception => e
|
68
|
+
warn "#{self.class} - #{e.class} - #{e.message}"
|
69
|
+
close
|
70
|
+
@io = nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def reconnect
|
74
|
+
@io = nil
|
75
|
+
connect
|
76
|
+
end
|
77
|
+
|
78
|
+
def connect
|
79
|
+
@io = TCPSocket.new(host, port).tap do |socket|
|
80
|
+
warn "#{self.class} - connect to #{uri.to_s}"
|
81
|
+
socket.sync = true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end ; end ; end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Vx ; module Lib ; module Logger
|
2
|
+
|
3
|
+
module Sanitizer
|
4
|
+
|
5
|
+
def self.hash(payload)
|
6
|
+
payload = {} unless payload.is_a?(Hash)
|
7
|
+
|
8
|
+
payload.keys.each do |key_name|
|
9
|
+
value = payload[key_name]
|
10
|
+
unless value.is_a?(String)
|
11
|
+
payload[key_name] = value.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
payload
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end ; end ; end
|
@@ -2,11 +2,11 @@ require 'oj'
|
|
2
2
|
|
3
3
|
module Vx ; module Lib ; module Logger
|
4
4
|
|
5
|
-
module
|
5
|
+
module StdoutFormatter
|
6
6
|
|
7
|
-
def self.call(message, payload)
|
7
|
+
def self.call(level, message, payload)
|
8
8
|
payload = ::Oj.dump(payload, mode: :compat)
|
9
|
-
"#{message} :--: #{payload}"
|
9
|
+
"[#{level}] #{message} :--: #{payload}\n"
|
10
10
|
end
|
11
11
|
|
12
12
|
end
|
data/spec/lib/instance_spec.rb
CHANGED
@@ -4,77 +4,91 @@ require 'stringio'
|
|
4
4
|
|
5
5
|
describe Vx::Lib::Logger::Instance do
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
7
|
+
before do
|
8
|
+
@out = StringIO.new
|
9
|
+
@log = Vx::Lib::Logger.get(@out)
|
10
|
+
assert @log
|
11
|
+
end
|
12
|
+
|
13
|
+
[:fatal, :warn, :debug, :error, :info].each do |m|
|
14
|
+
it "should write #{m} message" do
|
15
|
+
@log.public_send(m, "send #{m}")
|
16
|
+
text = "[#{m}] send #{m} :--: {\"thread_id\":#{tid}}\n"
|
17
|
+
assert_equal text, get_out
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should write message with params" do
|
22
|
+
@log.info "text message", param: :value
|
23
|
+
text = "[info] text message :--: {\"thread_id\":#{tid},\"fields\":{\"param\":\"value\"}}\n"
|
24
|
+
assert_equal text, get_out
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should write message with object in params" do
|
28
|
+
@log.info "object message", param: Exception.new("foo")
|
29
|
+
assert get_out
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should write message with exception in params" do
|
33
|
+
@log.info "text message", exception: Exception.new("got!")
|
34
|
+
text = "[info] text message :--: {\"thread_id\":#{tid},\"fields\":{\"exception\":\"Exception - got!\",\"backtrace\":\"\"}}\n"
|
35
|
+
assert_equal text, get_out
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should handle block" do
|
39
|
+
@log.handle "text message" do
|
40
|
+
sleep 0.1
|
41
|
+
end
|
42
|
+
assert_match(/duration/, get_out)
|
43
|
+
|
44
|
+
begin
|
45
|
+
@log.handle "text message", key: :value do
|
46
|
+
raise 'got!'
|
47
|
+
end
|
48
|
+
rescue Exception
|
49
|
+
end
|
50
|
+
|
51
|
+
body = get_out
|
52
|
+
assert_match(/duration/, body)
|
53
|
+
assert_match(/key/, body)
|
54
|
+
assert_match(/value/, body)
|
55
|
+
assert_match(/got\!/, body)
|
56
|
+
assert_match(/backtrace/, body)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should dump invalid unicode key" do
|
60
|
+
@log.info "Le Caf\xc3\xa9 \xa9", key: "Le Caf\xc3\xa9 \xa9"
|
61
|
+
text = "[info] Le Café \xA9 :--: {\"thread_id\":#{tid},\"fields\":{\"key\":\"Le Café \xA9\"}}\n"
|
62
|
+
assert_equal text, get_out
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should write message with logstash" do
|
66
|
+
begin
|
67
|
+
ENV['LOGSTASH_HOST'] = 'localhost:9999'
|
68
|
+
log = Vx::Lib::Logger.get(@out)
|
69
|
+
re = with_socket do
|
70
|
+
log.info "Hello"
|
71
|
+
end
|
72
|
+
assert_match(/Hello/, re)
|
73
|
+
assert_match(/Hello/, get_out)
|
74
|
+
ensure
|
75
|
+
ENV['LOGSTASH_HOST'] = nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_out
|
80
|
+
@out.rewind
|
81
|
+
body = @out.read
|
82
|
+
@out.rewind
|
83
|
+
body
|
84
|
+
end
|
85
|
+
|
86
|
+
def tid
|
87
|
+
Thread.current.object_id
|
88
|
+
end
|
89
|
+
|
90
|
+
def pid
|
91
|
+
Process.pid
|
92
|
+
end
|
79
93
|
|
80
94
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Vx::Lib::Logger::Logstash do
|
4
|
+
|
5
|
+
before do
|
6
|
+
ENV['LOGSTASH_HOST'] = 'localhost:9999'
|
7
|
+
end
|
8
|
+
|
9
|
+
after do
|
10
|
+
ENV['LOGSTASH_HOST'] = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should successfuly connect" do
|
14
|
+
re = with_socket do
|
15
|
+
log = Vx::Lib::Logger::Logstash.new
|
16
|
+
log.write("Hello\n")
|
17
|
+
log.close
|
18
|
+
end
|
19
|
+
assert_equal re, "Hello\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should successfuly lost connection" do
|
23
|
+
log = Vx::Lib::Logger::Logstash.new
|
24
|
+
|
25
|
+
re = with_socket do
|
26
|
+
log.write("Hello\n")
|
27
|
+
log.close
|
28
|
+
end
|
29
|
+
|
30
|
+
log.write("Lost\n")
|
31
|
+
|
32
|
+
re << with_socket do
|
33
|
+
log.write("World\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
log.close
|
37
|
+
|
38
|
+
assert_equal re, "Hello\nWorld\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,3 +2,25 @@ require File.expand_path("../../lib/vx/lib/logger", __FILE__)
|
|
2
2
|
|
3
3
|
require 'minitest/spec'
|
4
4
|
require 'minitest/autorun'
|
5
|
+
|
6
|
+
def with_socket
|
7
|
+
out = ""
|
8
|
+
server = TCPServer.new 9999
|
9
|
+
|
10
|
+
th = Thread.new do
|
11
|
+
loop do
|
12
|
+
client = server.accept
|
13
|
+
out << client.gets
|
14
|
+
client.close
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
yield
|
20
|
+
sleep 0.2
|
21
|
+
out
|
22
|
+
ensure
|
23
|
+
th.kill
|
24
|
+
server.close
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vx-lib-logger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Galinsky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oj
|
@@ -66,12 +66,15 @@ files:
|
|
66
66
|
- Rakefile
|
67
67
|
- lib/vx/lib/logger.rb
|
68
68
|
- lib/vx/lib/logger/instance.rb
|
69
|
-
- lib/vx/lib/logger/
|
69
|
+
- lib/vx/lib/logger/journal_formatter.rb
|
70
|
+
- lib/vx/lib/logger/logstash.rb
|
70
71
|
- lib/vx/lib/logger/rack/handle_exceptions.rb
|
71
|
-
- lib/vx/lib/logger/
|
72
|
+
- lib/vx/lib/logger/sanitizer.rb
|
73
|
+
- lib/vx/lib/logger/stdout_formatter.rb
|
72
74
|
- lib/vx/lib/logger/version.rb
|
73
75
|
- spec/lib/instance_spec.rb
|
74
76
|
- spec/lib/logger_spec.rb
|
77
|
+
- spec/lib/logstash_spec.rb
|
75
78
|
- spec/lib/rack_handle_exceptions_spec.rb
|
76
79
|
- spec/spec_helper.rb
|
77
80
|
- vexor.yml
|
@@ -103,6 +106,6 @@ summary: summary
|
|
103
106
|
test_files:
|
104
107
|
- spec/lib/instance_spec.rb
|
105
108
|
- spec/lib/logger_spec.rb
|
109
|
+
- spec/lib/logstash_spec.rb
|
106
110
|
- spec/lib/rack_handle_exceptions_spec.rb
|
107
111
|
- spec/spec_helper.rb
|
108
|
-
has_rdoc:
|