stackify-api-ruby 1.0.15 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/proto/stackify-agent.rb +102 -0
- data/lib/stackify-api-ruby.rb +53 -18
- data/lib/stackify/logger_client.rb +11 -53
- data/lib/stackify/logs_sender.rb +90 -1
- data/lib/stackify/msgs_queue.rb +10 -5
- data/lib/stackify/transport_selector.rb +17 -0
- data/lib/stackify/unix_socket_client.rb +97 -0
- data/lib/stackify/unix_socket_sender.rb +79 -0
- data/lib/stackify/utils/configuration.rb +49 -5
- data/lib/stackify/utils/methods.rb +9 -0
- data/lib/stackify/utils/protobuf_log_object.rb +85 -0
- data/lib/stackify/version.rb +1 -1
- data/lib/stackify/workers/logs_sender_worker.rb +2 -0
- data/stackify-api-ruby.gemspec +2 -0
- metadata +35 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 000465ac09f10d108d71cf5b9441315f01aa42d81b6ff90ce31c053724688536
|
4
|
+
data.tar.gz: 6b151709a6b4e297b3e1655b1de68297a43d65af1866abf034d64f16df04b438
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e42e021203b70b6d43535ea43163b42af23ba4528ef0e7a2a377223541ca3122d0773034e66ad0b6e58b77d9b43ea355456efbcad97b9d2432cf134ab3fcf6c3
|
7
|
+
data.tar.gz: ff51578f76cea1ceed8d89e78570237e2ef0b67266a1f9f92c0f866edd727925ae0a5c0c98c3af662643980a062120e3baef8ffb3cad08cce3310cf91c9015d0
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: stackify-agent.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
7
|
+
add_message "stackify.LogGroup" do
|
8
|
+
optional :environment, :string, 1
|
9
|
+
optional :server_name, :string, 2
|
10
|
+
optional :application_name, :string, 3
|
11
|
+
optional :application_location, :string, 4
|
12
|
+
optional :logger, :string, 5
|
13
|
+
optional :platform, :string, 6
|
14
|
+
repeated :logs, :message, 7, "stackify.LogGroup.Log"
|
15
|
+
optional :container, :message, 8, "stackify.LogGroup.Container"
|
16
|
+
optional :kubernetes, :message, 9, "stackify.LogGroup.Kubernetes"
|
17
|
+
end
|
18
|
+
add_message "stackify.LogGroup.Container" do
|
19
|
+
optional :image_id, :string, 1
|
20
|
+
optional :image_repository, :string, 2
|
21
|
+
optional :image_tag, :string, 3
|
22
|
+
optional :container_id, :string, 4
|
23
|
+
optional :container_name, :string, 5
|
24
|
+
end
|
25
|
+
add_message "stackify.LogGroup.Kubernetes" do
|
26
|
+
optional :pod_name, :string, 1
|
27
|
+
optional :pod_namespace, :string, 2
|
28
|
+
optional :cluster_name, :string, 3
|
29
|
+
end
|
30
|
+
add_message "stackify.LogGroup.Log" do
|
31
|
+
optional :message, :string, 1
|
32
|
+
optional :data, :string, 2
|
33
|
+
optional :thread_name, :string, 3
|
34
|
+
optional :date_millis, :int64, 4
|
35
|
+
optional :level, :string, 5
|
36
|
+
optional :transaction_id, :string, 6
|
37
|
+
optional :source_method, :string, 7
|
38
|
+
optional :source_line, :int32, 8
|
39
|
+
optional :id, :string, 9
|
40
|
+
repeated :tags, :string, 10
|
41
|
+
optional :error, :message, 11, "stackify.LogGroup.Log.Error"
|
42
|
+
end
|
43
|
+
add_message "stackify.LogGroup.Log.Error" do
|
44
|
+
optional :environment_detail, :message, 1, "stackify.LogGroup.Log.Error.EnvironmentDetail"
|
45
|
+
optional :date_millis, :int64, 2
|
46
|
+
optional :error_item, :message, 3, "stackify.LogGroup.Log.Error.ErrorItem"
|
47
|
+
optional :web_request_detail, :message, 4, "stackify.LogGroup.Log.Error.WebRequestDetail"
|
48
|
+
map :server_variables, :string, :string, 5
|
49
|
+
optional :customer_name, :string, 6
|
50
|
+
optional :username, :string, 7
|
51
|
+
end
|
52
|
+
add_message "stackify.LogGroup.Log.Error.EnvironmentDetail" do
|
53
|
+
optional :device_name, :string, 1
|
54
|
+
optional :application_name, :string, 2
|
55
|
+
optional :application_location, :string, 3
|
56
|
+
optional :configured_application_name, :string, 4
|
57
|
+
optional :configured_environment_name, :string, 5
|
58
|
+
end
|
59
|
+
add_message "stackify.LogGroup.Log.Error.ErrorItem" do
|
60
|
+
optional :message, :string, 1
|
61
|
+
optional :error_type, :string, 2
|
62
|
+
optional :error_type_code, :string, 3
|
63
|
+
map :data, :string, :string, 4
|
64
|
+
optional :source_method, :string, 5
|
65
|
+
repeated :stacktrace, :message, 6, "stackify.LogGroup.Log.Error.ErrorItem.TraceFrame"
|
66
|
+
optional :inner_error, :message, 7, "stackify.LogGroup.Log.Error.ErrorItem"
|
67
|
+
end
|
68
|
+
add_message "stackify.LogGroup.Log.Error.ErrorItem.TraceFrame" do
|
69
|
+
optional :code_filename, :string, 1
|
70
|
+
optional :line_number, :int32, 2
|
71
|
+
optional :method, :string, 3
|
72
|
+
end
|
73
|
+
add_message "stackify.LogGroup.Log.Error.WebRequestDetail" do
|
74
|
+
optional :user_ip_address, :string, 1
|
75
|
+
optional :http_method, :string, 2
|
76
|
+
optional :request_protocol, :string, 3
|
77
|
+
optional :request_url, :string, 4
|
78
|
+
optional :request_url_root, :string, 5
|
79
|
+
optional :referral_url, :string, 6
|
80
|
+
map :headers, :string, :string, 7
|
81
|
+
map :cookies, :string, :string, 8
|
82
|
+
map :querystring, :string, :string, 9
|
83
|
+
map :post_data, :string, :string, 10
|
84
|
+
map :session_data, :string, :string, 11
|
85
|
+
optional :post_data_raw, :string, 12
|
86
|
+
optional :mvc_action, :string, 13
|
87
|
+
optional :mvc_controller, :string, 14
|
88
|
+
optional :mvc_area, :string, 15
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
module Stackify
|
93
|
+
LogGroup = Google::Protobuf::DescriptorPool.generated_pool.lookup("stackify.LogGroup").msgclass
|
94
|
+
LogGroup::Container = Google::Protobuf::DescriptorPool.generated_pool.lookup("stackify.LogGroup.Container").msgclass
|
95
|
+
LogGroup::Kubernetes = Google::Protobuf::DescriptorPool.generated_pool.lookup("stackify.LogGroup.Kubernetes").msgclass
|
96
|
+
LogGroup::Log = Google::Protobuf::DescriptorPool.generated_pool.lookup("stackify.LogGroup.Log").msgclass
|
97
|
+
LogGroup::Log::Error = Google::Protobuf::DescriptorPool.generated_pool.lookup("stackify.LogGroup.Log.Error").msgclass
|
98
|
+
LogGroup::Log::Error::EnvironmentDetail = Google::Protobuf::DescriptorPool.generated_pool.lookup("stackify.LogGroup.Log.Error.EnvironmentDetail").msgclass
|
99
|
+
LogGroup::Log::Error::ErrorItem = Google::Protobuf::DescriptorPool.generated_pool.lookup("stackify.LogGroup.Log.Error.ErrorItem").msgclass
|
100
|
+
LogGroup::Log::Error::ErrorItem::TraceFrame = Google::Protobuf::DescriptorPool.generated_pool.lookup("stackify.LogGroup.Log.Error.ErrorItem.TraceFrame").msgclass
|
101
|
+
LogGroup::Log::Error::WebRequestDetail = Google::Protobuf::DescriptorPool.generated_pool.lookup("stackify.LogGroup.Log.Error.WebRequestDetail").msgclass
|
102
|
+
end
|
data/lib/stackify-api-ruby.rb
CHANGED
@@ -2,14 +2,19 @@ require 'stackify/version'
|
|
2
2
|
require 'stackify/utils/methods'
|
3
3
|
require 'core_ext/core_ext' unless defined? Rails
|
4
4
|
|
5
|
+
require 'google/protobuf'
|
6
|
+
require 'proto/stackify-agent.rb'
|
7
|
+
|
5
8
|
module Stackify
|
6
9
|
|
7
10
|
INTERNAL_LOG_PREFIX = '[Stackify]'.freeze
|
8
11
|
STATUSES = { working: 'working', terminating: 'terminating', terminated: 'terminated'}
|
9
12
|
MODES = { logging: :logging, metrics: :metrics, both: :both }
|
13
|
+
TRANSPORT = [DEFAULT = 'default', UNIX_SOCKET = 'agent_socket']
|
10
14
|
|
11
15
|
autoload :Backtrace, 'stackify/utils/backtrace'
|
12
16
|
autoload :MsgObject, 'stackify/utils/msg_object'
|
17
|
+
autoload :ProtobufLogObject, 'stackify/utils/protobuf_log_object'
|
13
18
|
autoload :Configuration, 'stackify/utils/configuration'
|
14
19
|
autoload :HttpClient, 'stackify/http_client'
|
15
20
|
autoload :Authorizable, 'stackify/authorization/authorizable'
|
@@ -24,7 +29,10 @@ module Stackify
|
|
24
29
|
autoload :AddMsgWorker, 'stackify/workers/add_msg_worker'
|
25
30
|
autoload :MsgsQueue, 'stackify/msgs_queue'
|
26
31
|
autoload :LoggerClient, 'stackify/logger_client'
|
32
|
+
autoload :UnixSocketClient, 'stackify/unix_socket_client'
|
33
|
+
autoload :TransportSelector, 'stackify/transport_selector'
|
27
34
|
autoload :LogsSender, 'stackify/logs_sender'
|
35
|
+
autoload :UnixSocketSender, 'stackify/unix_socket_sender'
|
28
36
|
autoload :LoggerProxy, 'stackify/logger_proxy'
|
29
37
|
autoload :StackifiedError, 'stackify/error'
|
30
38
|
autoload :StringException, 'stackify/error'
|
@@ -44,6 +52,7 @@ module Stackify
|
|
44
52
|
def setup
|
45
53
|
@workers = []
|
46
54
|
yield(configuration) if block_given?
|
55
|
+
configuration.validate_transport_type
|
47
56
|
if configuration.is_valid?
|
48
57
|
@status = STATUSES[:working]
|
49
58
|
else
|
@@ -53,7 +62,6 @@ module Stackify
|
|
53
62
|
end
|
54
63
|
raise msg
|
55
64
|
end
|
56
|
-
|
57
65
|
end
|
58
66
|
|
59
67
|
def msgs_queue
|
@@ -64,8 +72,16 @@ module Stackify
|
|
64
72
|
@logger_client ||= Stackify::LoggerClient.new
|
65
73
|
end
|
66
74
|
|
67
|
-
def
|
68
|
-
@
|
75
|
+
def unix_socket_client
|
76
|
+
@unix_socket_client ||= Stackify::UnixSocketClient.new
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_transport
|
80
|
+
@logger_client.get_transport
|
81
|
+
end
|
82
|
+
|
83
|
+
def send_unix_socket
|
84
|
+
@unix_socket ||= Stackify::UnixSocketSender.new
|
69
85
|
end
|
70
86
|
|
71
87
|
def logger
|
@@ -105,24 +121,43 @@ module Stackify
|
|
105
121
|
|
106
122
|
def run
|
107
123
|
Stackify::Utils.is_api_enabled
|
124
|
+
Stackify.internal_log :debug, "Stackify.run = #{Stackify.configuration.transport}"
|
108
125
|
if Stackify.configuration.api_enabled
|
109
126
|
if Stackify.is_valid?
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
127
|
+
# check transport types
|
128
|
+
case Stackify.configuration.transport
|
129
|
+
when Stackify::DEFAULT
|
130
|
+
if Stackify.is_valid?
|
131
|
+
at_exit { make_remained_job }
|
132
|
+
t1 = Thread.new { Stackify.authorize }
|
133
|
+
case Stackify.configuration.mode
|
134
|
+
when MODES[:both]
|
135
|
+
t2 = start_logging
|
136
|
+
t3 = start_metrics
|
137
|
+
when MODES[:logging]
|
138
|
+
t2 = start_logging
|
139
|
+
when MODES[:metrics]
|
140
|
+
t3 = start_metrics
|
141
|
+
end
|
142
|
+
|
143
|
+
t1.join
|
144
|
+
t3.join if t3
|
145
|
+
else
|
146
|
+
Stackify.log_internal_error "Stackify is not properly configured! Errors: #{Stackify.configuration.errors}"
|
147
|
+
end
|
148
|
+
when Stackify::UNIX_SOCKET
|
149
|
+
case Stackify.configuration.mode
|
150
|
+
when MODES[:logging]
|
151
|
+
start_logging
|
152
|
+
when MODES[:both]
|
153
|
+
start_logging
|
154
|
+
start_metrics
|
155
|
+
when MODES[:metrics]
|
156
|
+
start_metrics
|
157
|
+
end
|
158
|
+
else
|
159
|
+
Stackify.log_internal_error "Stackify is not properly configured! Errors: #{Stackify.configuration.errors}"
|
120
160
|
end
|
121
|
-
|
122
|
-
t1.join
|
123
|
-
t3.join if t3
|
124
|
-
else
|
125
|
-
Stackify.log_internal_error "Stackify is not properly configured! Errors: #{Stackify.configuration.errors}"
|
126
161
|
end
|
127
162
|
end
|
128
163
|
end
|
@@ -3,35 +3,21 @@ module Stackify
|
|
3
3
|
|
4
4
|
def initialize
|
5
5
|
@@errors_governor = Stackify::ErrorsGovernor.new
|
6
|
+
@@transport = Stackify::TransportSelector.new(Stackify.configuration.transport).transport
|
6
7
|
end
|
7
8
|
|
8
9
|
def log level, msg, call_trace
|
9
|
-
|
10
|
-
|
11
|
-
worker = Stackify::AddMsgWorker.new
|
12
|
-
task = log_message_task level, msg, call_trace
|
13
|
-
worker.async_perform ScheduleDelay.new, task
|
14
|
-
end
|
15
|
-
end
|
10
|
+
task = log_message_task level, msg, call_trace
|
11
|
+
@@transport.log level, msg, call_trace, task
|
16
12
|
end
|
17
13
|
|
18
14
|
def log_exception level= :error, ex
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
worker.async_perform ScheduleDelay.new, task
|
26
|
-
else
|
27
|
-
Stackify.internal_log :warn,
|
28
|
-
"LoggerClient: logging of exception with message \"#{ex.message}\" is skipped - flood_limit is exceeded"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
else
|
33
|
-
Stackify.log_internal_error 'LoggerClient: log_exception should get StackifiedError object'
|
34
|
-
end
|
15
|
+
task = log_exception_task level, ex
|
16
|
+
@@transport.log_exception level, ex, task
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_transport
|
20
|
+
@@transport
|
35
21
|
end
|
36
22
|
|
37
23
|
private
|
@@ -52,39 +38,11 @@ module Stackify
|
|
52
38
|
end
|
53
39
|
|
54
40
|
def log_message_task level, msg, call_trace, trans_id=nil, log_uuid=nil
|
55
|
-
|
56
|
-
if %w(error fatal).include?(level)
|
57
|
-
ex = if ruby_exception?(msg) && msg.class != Class
|
58
|
-
msg.set_backtrace(call_trace)
|
59
|
-
msg
|
60
|
-
else
|
61
|
-
e = StringException.new(msg)
|
62
|
-
e.set_backtrace(call_trace)
|
63
|
-
e
|
64
|
-
end
|
65
|
-
ex = StackifiedError.new(ex, binding())
|
66
|
-
Stackify.msgs_queue << Stackify::MsgObject.new(level, ex.message, caller[0], trans_id, log_uuid, ex).to_h
|
67
|
-
else
|
68
|
-
Stackify.msgs_queue << Stackify::MsgObject.new(level, msg, caller[0], trans_id, log_uuid).to_h
|
69
|
-
end
|
70
|
-
end
|
41
|
+
@@transport.log_message_task level, msg, call_trace, trans_id, log_uuid
|
71
42
|
end
|
72
43
|
|
73
44
|
def log_exception_task level, ex, trans_id=nil, log_uuid=nil
|
74
|
-
|
75
|
-
Stackify.msgs_queue << Stackify::MsgObject.new(level, ex.message, caller[0], trans_id, log_uuid, ex).to_h
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def ruby_exception? klass
|
80
|
-
klass = klass.class == Class ? klass : klass.class
|
81
|
-
klasses = [klass]
|
82
|
-
while klass != Object do
|
83
|
-
klasses << klass.superclass
|
84
|
-
klass = klass.superclass
|
85
|
-
end
|
86
|
-
klasses.include?(Exception)
|
45
|
+
@@transport.log_exception_task level, ex, trans_id, log_uuid
|
87
46
|
end
|
88
47
|
end
|
89
|
-
|
90
48
|
end
|
data/lib/stackify/logs_sender.rb
CHANGED
@@ -3,13 +3,102 @@ module Stackify
|
|
3
3
|
|
4
4
|
LOGS_URI = URI("#{Stackify.configuration.base_api_url}/Log/Save")
|
5
5
|
|
6
|
+
def initialize
|
7
|
+
@@errors_governor = Stackify::ErrorsGovernor.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def log level, msg, call_trace, task
|
11
|
+
Stackify::Utils.do_only_if_authorized_and_mode_is_on Stackify::MODES[:logging] do
|
12
|
+
if acceptable?(level, msg) && Stackify.working?
|
13
|
+
worker = Stackify::AddMsgWorker.new
|
14
|
+
worker.async_perform ScheduleDelay.new, task
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def log_exception level= :error, ex, task
|
20
|
+
if ex.is_a?(Stackify::StackifiedError)
|
21
|
+
Stackify::Utils.do_only_if_authorized_and_mode_is_on Stackify::MODES[:logging] do
|
22
|
+
if acceptable?(level, ex.message) && Stackify.working?
|
23
|
+
if @@errors_governor.can_send? ex
|
24
|
+
worker = Stackify::AddMsgWorker.new
|
25
|
+
worker.async_perform ScheduleDelay.new, task
|
26
|
+
else
|
27
|
+
Stackify.internal_log :warn,
|
28
|
+
"LoggerClient: logging of exception with message \"#{ex.message}\" is skipped - flood_limit is exceeded"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
else
|
33
|
+
Stackify.log_internal_error 'LoggerClient: log_exception should get StackifiedError object'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def has_error msg
|
38
|
+
!msg['Ex'].nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_epoch msg
|
42
|
+
msg['EpochMs']
|
43
|
+
end
|
44
|
+
|
45
|
+
def log_message_task level, msg, call_trace, trans_id=nil, log_uuid=nil
|
46
|
+
Stackify::ScheduleTask.new ({limit: 1}) do
|
47
|
+
if %w(error fatal).include?(level)
|
48
|
+
ex = if ruby_exception?(msg) && msg.class != Class
|
49
|
+
msg.set_backtrace(call_trace)
|
50
|
+
msg
|
51
|
+
else
|
52
|
+
e = StringException.new(msg)
|
53
|
+
e.set_backtrace(call_trace)
|
54
|
+
e
|
55
|
+
end
|
56
|
+
ex = StackifiedError.new(ex, binding())
|
57
|
+
Stackify.msgs_queue << Stackify::MsgObject.new(level, ex.message, caller[0], trans_id, log_uuid, ex).to_h
|
58
|
+
else
|
59
|
+
Stackify.msgs_queue << Stackify::MsgObject.new(level, msg, caller[0], trans_id, log_uuid).to_h
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def log_exception_task level, ex, trans_id=nil, log_uuid=nil
|
65
|
+
Stackify::ScheduleTask.new ({limit: 1}) do
|
66
|
+
Stackify.msgs_queue << Stackify::MsgObject.new(level, ex.message, caller[0], trans_id, log_uuid, ex).to_h
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
6
70
|
def send_logs msgs, attempts = 3
|
7
71
|
worker = Stackify::LogsSenderWorker.new
|
8
72
|
task = send_logs_task attempts, msgs
|
9
73
|
worker.async_perform ScheduleDelay.new, task
|
10
74
|
end
|
11
75
|
|
12
|
-
|
76
|
+
private
|
77
|
+
|
78
|
+
def acceptable? level, msg
|
79
|
+
Stackify.is_valid? && is_correct_log_level?(level) &&
|
80
|
+
is_not_internal_log_message?(msg)
|
81
|
+
end
|
82
|
+
|
83
|
+
def is_not_internal_log_message? msg
|
84
|
+
msg.try(:index, ::Stackify::INTERNAL_LOG_PREFIX).nil?
|
85
|
+
end
|
86
|
+
|
87
|
+
def is_correct_log_level? level
|
88
|
+
config_level = Logger.const_get Stackify.configuration.log_level.to_s.upcase
|
89
|
+
current_level = Logger.const_get level.to_s.upcase
|
90
|
+
current_level >= config_level
|
91
|
+
end
|
92
|
+
|
93
|
+
def ruby_exception? klass
|
94
|
+
klass = klass.class == Class ? klass : klass.class
|
95
|
+
klasses = [klass]
|
96
|
+
while klass != Object do
|
97
|
+
klasses << klass.superclass
|
98
|
+
klass = klass.superclass
|
99
|
+
end
|
100
|
+
klasses.include?(Exception)
|
101
|
+
end
|
13
102
|
|
14
103
|
def properties
|
15
104
|
{
|
data/lib/stackify/msgs_queue.rb
CHANGED
@@ -34,7 +34,7 @@ module Stackify
|
|
34
34
|
Stackify.internal_log :info, '[MsgsQueue] All remained logs are going to be sent'
|
35
35
|
Stackify.shutdown_all
|
36
36
|
if self.length > 0
|
37
|
-
Stackify.
|
37
|
+
Stackify.get_transport.send_logs(pop_all)
|
38
38
|
Stackify.status = Stackify::STATUSES[:terminated]
|
39
39
|
end
|
40
40
|
end
|
@@ -47,7 +47,12 @@ module Stackify
|
|
47
47
|
Stackify.internal_log :debug, "[MsgsQueue] add_msg() Newly created worker <#{@worker.name}>"
|
48
48
|
end
|
49
49
|
self.synchronize do
|
50
|
-
Stackify
|
50
|
+
case Stackify.configuration.transport
|
51
|
+
when Stackify::DEFAULT
|
52
|
+
Stackify::Utils.do_only_if_authorized_and_mode_is_on Stackify::MODES[:logging] do
|
53
|
+
old_push(msg)
|
54
|
+
end
|
55
|
+
when Stackify::UNIX_SOCKET
|
51
56
|
old_push(msg)
|
52
57
|
end
|
53
58
|
end
|
@@ -109,13 +114,13 @@ module Stackify
|
|
109
114
|
if length > 0
|
110
115
|
msg = pop
|
111
116
|
chunk << msg
|
112
|
-
chunk_weight += (msg
|
113
|
-
break if msg
|
117
|
+
chunk_weight += Stackify.get_transport.has_error(msg) ? ERROR_SIZE : LOG_SIZE
|
118
|
+
break if Stackify.get_transport.get_epoch(msg) > started_at || CHUNK_MIN_WEIGHT > 50
|
114
119
|
else
|
115
120
|
break
|
116
121
|
end
|
117
122
|
end
|
118
|
-
Stackify.
|
123
|
+
Stackify.get_transport.send_logs(chunk) if chunk.length > 0
|
119
124
|
chunk_weight
|
120
125
|
end
|
121
126
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Stackify
|
2
|
+
class TransportSelector
|
3
|
+
|
4
|
+
attr_reader :transport
|
5
|
+
|
6
|
+
def initialize type
|
7
|
+
case type
|
8
|
+
when Stackify::DEFAULT
|
9
|
+
Stackify::Utils.do_only_if_authorized_and_mode_is_on Stackify::MODES[:logging] do
|
10
|
+
@transport = Stackify::LogsSender.new
|
11
|
+
end
|
12
|
+
when Stackify::UNIX_SOCKET
|
13
|
+
@transport = Stackify::UnixSocketClient.new
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Stackify
|
2
|
+
class UnixSocketClient
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
Stackify.internal_log :info, '[UnixSocketClient]: initialize()'
|
6
|
+
@@errors_governor = Stackify::ErrorsGovernor.new
|
7
|
+
@@sender = Stackify::UnixSocketSender.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def log level, msg, call_trace, task
|
11
|
+
if acceptable?(level, msg) && Stackify.working?
|
12
|
+
worker = Stackify::AddMsgWorker.new
|
13
|
+
worker.async_perform ScheduleDelay.new, task
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def log_exception level= :error, ex, task
|
18
|
+
if ex.is_a?(Stackify::StackifiedError)
|
19
|
+
if acceptable?(level, ex.message) && Stackify.working?
|
20
|
+
if @@errors_governor.can_send? ex
|
21
|
+
worker = Stackify::AddMsgWorker.new
|
22
|
+
worker.async_perform ScheduleDelay.new, task
|
23
|
+
else
|
24
|
+
Stackify.internal_log :warn,
|
25
|
+
"UnixSocketClient: logging of exception with message \"#{ex.message}\" is skipped - flood_limit is exceeded"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
Stackify.log_internal_error 'UnixSocketClient: log_exception should get StackifiedError object'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def has_error msg
|
34
|
+
!msg.error.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_epoch msg
|
38
|
+
msg.date_millis
|
39
|
+
end
|
40
|
+
|
41
|
+
def send_logs msgs, attempts = 3
|
42
|
+
@@sender.send_logs msgs, attempts
|
43
|
+
end
|
44
|
+
|
45
|
+
def log_message_task level, msg, call_trace, trans_id=nil, log_uuid=nil
|
46
|
+
Stackify::ScheduleTask.new ({limit: 1}) do
|
47
|
+
if %w(error fatal).include?(level)
|
48
|
+
ex = if ruby_exception?(msg) && msg.class != Class
|
49
|
+
msg.set_backtrace(call_trace)
|
50
|
+
msg
|
51
|
+
else
|
52
|
+
e = StringException.new(msg)
|
53
|
+
e.set_backtrace(call_trace)
|
54
|
+
e
|
55
|
+
end
|
56
|
+
ex = StackifiedError.new(ex, binding())
|
57
|
+
Stackify.msgs_queue << Stackify::ProtobufLogObject.new(level, ex.message, caller[0], trans_id, log_uuid, ex).to_obj
|
58
|
+
else
|
59
|
+
Stackify.msgs_queue << Stackify::ProtobufLogObject.new(level, msg, caller[0], trans_id, log_uuid).to_obj
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def log_exception_task level, ex, trans_id=nil, log_uuid=nil
|
65
|
+
Stackify::ScheduleTask.new ({limit: 1}) do
|
66
|
+
Stackify.msgs_queue << Stackify::ProtobufLogObject.new(level, ex.message, caller[0], trans_id, log_uuid, ex).to_obj
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def acceptable? level, msg
|
73
|
+
Stackify.is_valid? && is_correct_log_level?(level) &&
|
74
|
+
is_not_internal_log_message?(msg)
|
75
|
+
end
|
76
|
+
|
77
|
+
def is_not_internal_log_message? msg
|
78
|
+
msg.try(:index, ::Stackify::INTERNAL_LOG_PREFIX).nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
def is_correct_log_level? level
|
82
|
+
config_level = Logger.const_get Stackify.configuration.log_level.to_s.upcase
|
83
|
+
current_level = Logger.const_get level.to_s.upcase
|
84
|
+
current_level >= config_level
|
85
|
+
end
|
86
|
+
|
87
|
+
def ruby_exception? klass
|
88
|
+
klass = klass.class == Class ? klass : klass.class
|
89
|
+
klasses = [klass]
|
90
|
+
while klass != Object do
|
91
|
+
klasses << klass.superclass
|
92
|
+
klass = klass.superclass
|
93
|
+
end
|
94
|
+
klasses.include?(Exception)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'net_http_unix'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
#
|
5
|
+
# This class will handle the sending of protobuf message to unix domain socket
|
6
|
+
#
|
7
|
+
module Stackify
|
8
|
+
class UnixSocketSender < Worker
|
9
|
+
|
10
|
+
# send_logs() Function to put the msg in the Worker
|
11
|
+
def send_logs msgs, attempts = 3
|
12
|
+
worker = Stackify::LogsSenderWorker.new('UnixSocketSender worker')
|
13
|
+
task = send_logs_task attempts, msgs
|
14
|
+
worker.async_perform ScheduleDelay.new, task
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def properties
|
20
|
+
{
|
21
|
+
success_condition: lambda { |result| result.try(:status) == 200 },
|
22
|
+
limit: 1
|
23
|
+
}.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
def send_logs_task attempts = nil, msgs
|
27
|
+
properties[:attempts] = attempts if attempts
|
28
|
+
Stackify::ScheduleTask.new properties do
|
29
|
+
data = create_log_group msgs
|
30
|
+
send_request data
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# create_log_group() This function will create a log group protobuf object
|
35
|
+
# @msgs {Object} Protobuf message
|
36
|
+
# return {Object} Return an object
|
37
|
+
def create_log_group msgs
|
38
|
+
# @details {Object} it will return the properties based in Stackify.setup() configuration
|
39
|
+
details = Stackify::Utils.get_app_settings
|
40
|
+
log_group = Stackify::LogGroup.new
|
41
|
+
msgs.each do |msg|
|
42
|
+
log_group.logs << msg
|
43
|
+
end
|
44
|
+
log_group.environment = details['env']
|
45
|
+
log_group.server_name = details['server_name']
|
46
|
+
log_group.application_name = details['app_name']
|
47
|
+
log_group.application_location = details['app_location']
|
48
|
+
log_group.logger = 'Ruby logger'
|
49
|
+
log_group.platform = 'ruby'
|
50
|
+
log_group
|
51
|
+
end
|
52
|
+
|
53
|
+
# send_request() This function will send http request via unix domain socket
|
54
|
+
# @msgs {Object} Protobuf message
|
55
|
+
# return {Object} Return an object {status, message}
|
56
|
+
def send_request log_group
|
57
|
+
begin
|
58
|
+
# Convert data into binary and send it to unix domain socket
|
59
|
+
message = Stackify::LogGroup.encode(log_group)
|
60
|
+
client = NetX::HTTPUnix.new('unix://' + Stackify.configuration.unix_socket_path)
|
61
|
+
req = Net::HTTP::Post.new(Stackify.configuration.unix_socket_url)
|
62
|
+
req.set_content_type('application/x-protobuf')
|
63
|
+
req.body = message
|
64
|
+
response = client.request(req)
|
65
|
+
Stackify.internal_log :debug, "[UnixSocketSender] status_code = #{response.code}"
|
66
|
+
if response.code.to_i == 200
|
67
|
+
Stackify.internal_log :debug, "[UnixSocketSender]: Successfully send message via unix domain socket."
|
68
|
+
return OpenStruct.new({status: 200, msg: 'OK'})
|
69
|
+
else
|
70
|
+
Stackify.internal_log :debug, "[UnixSocketSender] Sending failed."
|
71
|
+
return OpenStruct.new({status: 500, msg: 'Not OK'})
|
72
|
+
end
|
73
|
+
rescue => exception
|
74
|
+
Stackify.log_internal_error "[UnixSocketSender] send_logs() Error: #{exception}"
|
75
|
+
return OpenStruct.new({status: 500, msg: exception})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -3,14 +3,16 @@ module Stackify
|
|
3
3
|
class Configuration
|
4
4
|
|
5
5
|
attr_accessor :api_key, :app_name, :app_location, :env, :log_level, :logger,
|
6
|
-
:proxy, :mode, :base_api_url, :api_enabled
|
6
|
+
:proxy, :mode, :base_api_url, :api_enabled, :transport, :errors
|
7
7
|
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :send_interval, :flood_limit, :queue_max_size, :unix_socket_path, :unix_socket_url
|
9
9
|
|
10
10
|
def initialize
|
11
11
|
@base_api_url = 'https://api.stackify.com'
|
12
12
|
@errors = []
|
13
|
+
@app_name = ''
|
13
14
|
@api_key = ''
|
15
|
+
@transport = 'default'
|
14
16
|
@env = :production
|
15
17
|
@flood_limit = 100
|
16
18
|
@queue_max_size = 10000
|
@@ -20,14 +22,25 @@ module Stackify
|
|
20
22
|
@mode = MODES[:both]
|
21
23
|
@logger = Logger.new(STDOUT)
|
22
24
|
@logger.level = Logger::UNKNOWN
|
25
|
+
@unix_socket_path = '/usr/local/stackify/stackify.sock'
|
26
|
+
@unix_socket_url = '/log'
|
23
27
|
end
|
24
28
|
|
25
29
|
def is_valid?
|
26
|
-
|
27
|
-
|
30
|
+
case Stackify.configuration.transport
|
31
|
+
when Stackify::DEFAULT
|
32
|
+
validate_default_transport
|
33
|
+
when Stackify::UNIX_SOCKET
|
34
|
+
validate_unix_domain_socket_transport
|
35
|
+
end
|
28
36
|
@errors.empty?
|
29
37
|
end
|
30
38
|
|
39
|
+
def validate_transport_type
|
40
|
+
return true if ['agent_socket', 'default'].include? @transport
|
41
|
+
@errors << 'Transport should be one of these values: [agent_socket, default]. Should be a String.'
|
42
|
+
end
|
43
|
+
|
31
44
|
private
|
32
45
|
|
33
46
|
def validate_config_types
|
@@ -36,6 +49,27 @@ module Stackify
|
|
36
49
|
validate_mode_type
|
37
50
|
end
|
38
51
|
|
52
|
+
# Perform validation if transport type is default
|
53
|
+
# Required parameters are: env, app_name, api_key, log_level
|
54
|
+
def validate_default_transport
|
55
|
+
validate_app_name &&
|
56
|
+
validate_transport_type &&
|
57
|
+
validate_api_key &&
|
58
|
+
validate_env &&
|
59
|
+
validate_log_level &&
|
60
|
+
validate_mode_type
|
61
|
+
end
|
62
|
+
|
63
|
+
# Perform validation if transport type is agent_socket
|
64
|
+
# Required parameters are: env, app_name, log_level
|
65
|
+
def validate_unix_domain_socket_transport
|
66
|
+
validate_env &&
|
67
|
+
validate_transport_type &&
|
68
|
+
validate_app_name &&
|
69
|
+
validate_log_level &&
|
70
|
+
validate_mode_type
|
71
|
+
end
|
72
|
+
|
39
73
|
def validate_mode_type
|
40
74
|
return true if @mode.is_a? Symbol
|
41
75
|
@errors << 'Mode should be a Symbol'
|
@@ -43,7 +77,17 @@ module Stackify
|
|
43
77
|
|
44
78
|
def validate_api_key
|
45
79
|
return true if @api_key.is_a?(String) && !@api_key.empty?
|
46
|
-
@errors << '
|
80
|
+
@errors << 'Api_key should be a String and not empty'
|
81
|
+
end
|
82
|
+
|
83
|
+
def validate_app_name
|
84
|
+
return true if @app_name.is_a?(String) && !@app_name.empty?
|
85
|
+
@errors << 'App_name should be a String and not empty'
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate_env
|
89
|
+
return true if @env.is_a?(Symbol) && !@env.empty?
|
90
|
+
@errors << 'Env should be a Symbol and not empty'
|
47
91
|
end
|
48
92
|
|
49
93
|
def validate_log_level
|
@@ -33,4 +33,13 @@ module Stackify::Utils
|
|
33
33
|
found = exclude.select{|e| e =~ /#{cmd}/i}
|
34
34
|
Stackify.configuration.api_enabled = false if found.count > 0
|
35
35
|
end
|
36
|
+
|
37
|
+
def self.get_app_settings
|
38
|
+
@env = {
|
39
|
+
'env' => Stackify.configuration.env,
|
40
|
+
'app_name' => Stackify.configuration.app_name,
|
41
|
+
'server_name' => Socket.gethostname,
|
42
|
+
'app_location' => Stackify.configuration.app_location || Dir.pwd
|
43
|
+
}
|
44
|
+
end
|
36
45
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Stackify
|
2
|
+
class ProtobufLogObject
|
3
|
+
def initialize level, msg, caller_str, trans_id=nil, log_uuid=nil, ex=nil
|
4
|
+
@level, @msg, @caller_str, @ex = level, msg, caller_str, ex, @trans_id = trans_id,
|
5
|
+
@log_uuid = log_uuid
|
6
|
+
end
|
7
|
+
|
8
|
+
# Create a LogMsgGroup Protobuf Object
|
9
|
+
def to_obj
|
10
|
+
begin
|
11
|
+
log = Stackify::LogGroup::Log.new
|
12
|
+
log.message = @msg
|
13
|
+
log.thread_name = Thread.current.object_id.to_s
|
14
|
+
log.date_millis = (Time.now.to_f * 1000).to_i
|
15
|
+
log.level = @level.to_s.upcase!
|
16
|
+
log.source_method = Stackify::Backtrace.method_name(@caller_str).to_s
|
17
|
+
log.source_line = Stackify::Backtrace.line_number(@caller_str).to_i
|
18
|
+
log.transaction_id = @trans_id unless @trans_id.nil?
|
19
|
+
log.id = @log_uuid unless @log_uuid.nil?
|
20
|
+
if @ex.try(:to_h)
|
21
|
+
ex = @ex.try(:to_h)
|
22
|
+
log_error = Stackify::LogGroup::Log::Error.new
|
23
|
+
log_error.date_millis = ex['OccurredEpochMillis'].to_i
|
24
|
+
if ex['EnvironmentDetail']
|
25
|
+
env = ex['EnvironmentDetail']
|
26
|
+
env_detail = Stackify::LogGroup::Log::Error::EnvironmentDetail.new
|
27
|
+
env_detail.device_name = env['DeviceName'].to_s
|
28
|
+
env_detail.application_name = env['AppName'].to_s
|
29
|
+
env_detail.application_location = env['AppLocation'].to_s
|
30
|
+
env_detail.configured_application_name = env['ConfiguredAppName'].to_s
|
31
|
+
env_detail.configured_environment_name = env['ConfiguredEnvironmentName'].to_s
|
32
|
+
log_error.environment_detail = env_detail
|
33
|
+
end
|
34
|
+
if ex['Error']
|
35
|
+
err = ex['Error']
|
36
|
+
error_item = Stackify::LogGroup::Log::Error::ErrorItem.new
|
37
|
+
error_item.message = err['Message'].to_s
|
38
|
+
error_item.error_type = err['ErrorType'].to_s
|
39
|
+
error_item.error_type_code = err['ErrorTypeCode'].to_s
|
40
|
+
if err['Data']
|
41
|
+
map_data = Google::Protobuf::Map.new(:string, :string)
|
42
|
+
err['Data'].each { |key, value| map_data["#{key}"] = value }
|
43
|
+
error_item.data = map_data
|
44
|
+
end
|
45
|
+
error_item.inner_error = err['InnerError']
|
46
|
+
error_item.source_method = err['SourceMethod'].to_s
|
47
|
+
if err['StackTrace']
|
48
|
+
stack = err['StackTrace']
|
49
|
+
stack.each do |stk|
|
50
|
+
trace_frame = Stackify::LogGroup::Log::Error::ErrorItem::TraceFrame.new
|
51
|
+
trace_frame.code_filename = stk['CodeFileName'].to_s
|
52
|
+
trace_frame.line_number = stk['LineNum'].to_i
|
53
|
+
trace_frame.method = stk['Method'].to_s
|
54
|
+
error_item.stacktrace.push(trace_frame)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
log_error.error_item = error_item
|
58
|
+
end
|
59
|
+
if ex['WebRequestDetail']
|
60
|
+
req_details = ex['WebRequestDetail']
|
61
|
+
web_request = Stackify::LogGroup::Log::Error::WebRequestDetail.new
|
62
|
+
web_request.user_ip_address = req_details['UserIPAddress'].to_s
|
63
|
+
web_request.http_method = req_details['HttpMethod'].to_s
|
64
|
+
web_request.request_url = req_details['RequestUrl'].to_s
|
65
|
+
web_request.request_url_root = req_details['RequestUrlRoot'].to_s
|
66
|
+
web_request.referral_url = req_details['ReferralUrl'].to_s
|
67
|
+
web_request.post_data_raw = req_details['PostDataRaw'].to_s
|
68
|
+
log_error.web_request_detail = web_request
|
69
|
+
end
|
70
|
+
if !ex['ServerVariables'].empty?
|
71
|
+
map_server_vars = Google::Protobuf::Map.new(:string, :string)
|
72
|
+
ex['ServerVariables'].each { |key, value| map_server_vars["#{key.to_s}"] = value.to_s }
|
73
|
+
log_error.server_variables = map_server_vars
|
74
|
+
end
|
75
|
+
|
76
|
+
log.error = log_error
|
77
|
+
end
|
78
|
+
log
|
79
|
+
rescue => exception
|
80
|
+
Stackify.internal_log :info, "[ProtobufLogObject] Error: "
|
81
|
+
Stackify.internal_log :info, exception
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/stackify/version.rb
CHANGED
data/stackify-api-ruby.gemspec
CHANGED
@@ -22,4 +22,6 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
23
23
|
spec.add_development_dependency 'rake', '~> 0'
|
24
24
|
spec.add_runtime_dependency 'faraday', '~> 0.8'
|
25
|
+
spec.add_runtime_dependency 'google-protobuf', '~> 3.0'
|
26
|
+
spec.add_runtime_dependency 'net_http_unix', '~> 0.2'
|
25
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stackify-api-ruby
|
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
|
- Stackify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: google-protobuf
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: net_http_unix
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.2'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.2'
|
55
83
|
description: Stackify Logs and Metrics API for Ruby
|
56
84
|
email:
|
57
85
|
- support@stackify.com
|
@@ -71,6 +99,7 @@ files:
|
|
71
99
|
- lib/core_ext/object.rb
|
72
100
|
- lib/generators/stackify/stackify_generator.rb
|
73
101
|
- lib/generators/stackify/templates/stackify.rb
|
102
|
+
- lib/proto/stackify-agent.rb
|
74
103
|
- lib/stackify-api-ruby.rb
|
75
104
|
- lib/stackify/authorization/authorizable.rb
|
76
105
|
- lib/stackify/authorization/authorization_client.rb
|
@@ -94,10 +123,14 @@ files:
|
|
94
123
|
- lib/stackify/schedule_delay.rb
|
95
124
|
- lib/stackify/schedule_task.rb
|
96
125
|
- lib/stackify/scheduler.rb
|
126
|
+
- lib/stackify/transport_selector.rb
|
127
|
+
- lib/stackify/unix_socket_client.rb
|
128
|
+
- lib/stackify/unix_socket_sender.rb
|
97
129
|
- lib/stackify/utils/backtrace.rb
|
98
130
|
- lib/stackify/utils/configuration.rb
|
99
131
|
- lib/stackify/utils/methods.rb
|
100
132
|
- lib/stackify/utils/msg_object.rb
|
133
|
+
- lib/stackify/utils/protobuf_log_object.rb
|
101
134
|
- lib/stackify/version.rb
|
102
135
|
- lib/stackify/workers/add_msg_worker.rb
|
103
136
|
- lib/stackify/workers/auth_worker.rb
|