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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd19881ee793a2b23b9137218fd184427d9a9502efd1b81ba2064f23626d1228
4
- data.tar.gz: 9c3757c006c8f013afb097cf8a0cb7e016f1b1314375dfacfe3bd2d87403a9c8
3
+ metadata.gz: 000465ac09f10d108d71cf5b9441315f01aa42d81b6ff90ce31c053724688536
4
+ data.tar.gz: 6b151709a6b4e297b3e1655b1de68297a43d65af1866abf034d64f16df04b438
5
5
  SHA512:
6
- metadata.gz: bee61b9d0b9b18a3ad4db32dd6b7680b3e6c7db50979cdf1a8f9f222c97465c295474f05c757c734fa26b2082a4e5cbdf541083173c295d0bb48071bc64f04db
7
- data.tar.gz: 87ac37dd7b3ec51fc91f79eadad7316c587e25ee2e55844a974437cd4ad731c9ece070178ff51366f6132696cc93bd21c2cdb5eaa8c92df46d8b586ef265415d
6
+ metadata.gz: e42e021203b70b6d43535ea43163b42af23ba4528ef0e7a2a377223541ca3122d0773034e66ad0b6e58b77d9b43ea355456efbcad97b9d2432cf134ab3fcf6c3
7
+ data.tar.gz: ff51578f76cea1ceed8d89e78570237e2ef0b67266a1f9f92c0f866edd727925ae0a5c0c98c3af662643980a062120e3baef8ffb3cad08cce3310cf91c9015d0
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stackify-api-ruby (1.0.15)
4
+ stackify-api-ruby (1.1.0)
5
5
  faraday (~> 0.8)
6
6
 
7
7
  GEM
@@ -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
@@ -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 logs_sender
68
- @logs_sender ||= Stackify::LogsSender.new
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
- at_exit { make_remained_job }
111
- t1 = Thread.new { Stackify.authorize }
112
- case Stackify.configuration.mode
113
- when MODES[:both]
114
- t2 = start_logging
115
- t3 = start_metrics
116
- when MODES[:logging]
117
- t2 = start_logging
118
- when MODES[:metrics]
119
- t3 = start_metrics
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
- Stackify::Utils.do_only_if_authorized_and_mode_is_on Stackify::MODES[:logging] do
10
- if acceptable?(level, msg) && Stackify.working?
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
- if ex.is_a?(Stackify::StackifiedError)
20
- Stackify::Utils.do_only_if_authorized_and_mode_is_on Stackify::MODES[:logging] do
21
- if acceptable?(level, ex.message) && Stackify.working?
22
- if @@errors_governor.can_send? ex
23
- worker = Stackify::AddMsgWorker.new
24
- task = log_exception_task level, ex
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
- Stackify::ScheduleTask.new ({limit: 1}) do
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
- Stackify::ScheduleTask.new ({limit: 1}) do
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
@@ -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
- private
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
  {
@@ -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.logs_sender.send_logs(pop_all)
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::Utils.do_only_if_authorized_and_mode_is_on Stackify::MODES[:logging] do
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['Ex'].nil? ? LOG_SIZE : ERROR_SIZE)
113
- break if msg['EpochMs'] > started_at || CHUNK_MIN_WEIGHT > 50
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.logs_sender.send_logs(chunk) if chunk.length > 0
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 :errors, :send_interval, :flood_limit, :queue_max_size
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
- @errors = []
27
- validate_mode if validate_config_types
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 << 'API_KEY should be a String and not empty'
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
@@ -1,3 +1,3 @@
1
1
  module Stackify
2
- VERSION = '1.0.15'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -3,6 +3,8 @@ module Stackify
3
3
 
4
4
  def initialize name = 'LogsSender worker'
5
5
  super
6
+ @name = name
7
+ @name += " ##{self.id}"
6
8
  @type = :logs_send
7
9
  end
8
10
 
@@ -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.15
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-09-16 00:00:00.000000000 Z
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