Skip to content

Commit 44ffe1e

Browse files
jaygel179darinhoward
authored andcommitted
Ruby API - Add new transport AGENT_HTTP (#27)
* Ruby API - Add new transport AGENT_HTTP Changes: - added new transport http_agent - refactor transport and reuse codes - added option to get value from environment variables - fix formatting - remove unused requires - fix typo
1 parent 1ffbbaf commit 44ffe1e

File tree

8 files changed

+137
-69
lines changed

8 files changed

+137
-69
lines changed

lib/stackify-api-ruby.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module Stackify
1010
INTERNAL_LOG_PREFIX = '[Stackify]'.freeze
1111
STATUSES = { working: 'working', terminating: 'terminating', terminated: 'terminated'}
1212
MODES = { logging: :logging, metrics: :metrics, both: :both }
13-
TRANSPORT = [DEFAULT = 'default', UNIX_SOCKET = 'agent_socket']
13+
TRANSPORT = [DEFAULT = 'default', UNIX_SOCKET = 'agent_socket', AGENT_HTTP = 'agent_http']
1414

1515
autoload :Backtrace, 'stackify/utils/backtrace'
1616
autoload :MsgObject, 'stackify/utils/msg_object'
@@ -29,10 +29,12 @@ module Stackify
2929
autoload :AddMsgWorker, 'stackify/workers/add_msg_worker'
3030
autoload :MsgsQueue, 'stackify/msgs_queue'
3131
autoload :LoggerClient, 'stackify/logger_client'
32-
autoload :UnixSocketClient, 'stackify/unix_socket_client'
32+
autoload :AgentClient, 'stackify/agent_client'
3333
autoload :TransportSelector, 'stackify/transport_selector'
3434
autoload :LogsSender, 'stackify/logs_sender'
35+
autoload :AgentBaseSender, 'stackify/agent_base_sender'
3536
autoload :UnixSocketSender, 'stackify/unix_socket_sender'
37+
autoload :AgentHTTPSender, 'stackify/agent_http_sender'
3638
autoload :LoggerProxy, 'stackify/logger_proxy'
3739
autoload :StackifiedError, 'stackify/error'
3840
autoload :StringException, 'stackify/error'
@@ -72,8 +74,8 @@ def logger_client
7274
@logger_client ||= Stackify::LoggerClient.new
7375
end
7476

75-
def unix_socket_client
76-
@unix_socket_client ||= Stackify::UnixSocketClient.new
77+
def agent_client
78+
@agent_client ||= Stackify::AgentClient.new
7779
end
7880

7981
def get_transport
@@ -145,7 +147,7 @@ def run
145147
else
146148
Stackify.log_internal_error "Stackify is not properly configured! Errors: #{Stackify.configuration.errors}"
147149
end
148-
when Stackify::UNIX_SOCKET
150+
when Stackify::UNIX_SOCKET, Stackify::AGENT_HTTP
149151
case Stackify.configuration.mode
150152
when MODES[:logging]
151153
start_logging

lib/stackify/agent_base_sender.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#
2+
# This class will handle the sending of protobuf message to agent
3+
#
4+
module Stackify
5+
class AgentBaseSender < Worker
6+
7+
# send_logs() Function to put the msg in the Worker
8+
def send_logs msgs, attempts = 3
9+
worker = Stackify::LogsSenderWorker.new('UnixSocketSender worker')
10+
task = send_logs_task attempts, msgs
11+
worker.async_perform ScheduleDelay.new, task
12+
end
13+
14+
private
15+
16+
def properties
17+
{
18+
success_condition: lambda { |result| result.try(:status) == 200 },
19+
limit: 1
20+
}.dup
21+
end
22+
23+
def send_logs_task attempts = nil, msgs
24+
properties[:attempts] = attempts if attempts
25+
Stackify::ScheduleTask.new properties do
26+
data = create_log_group msgs
27+
send_request data
28+
end
29+
end
30+
31+
# create_log_group() This function will create a log group protobuf object
32+
# @msgs {Object} Protobuf message
33+
# return {Object} Return an object
34+
def create_log_group msgs
35+
# @details {Object} it will return the properties based in Stackify.setup() configuration
36+
details = Stackify::Utils.get_app_settings
37+
log_group = Stackify::LogGroup.new
38+
msgs.each do |msg|
39+
log_group.logs << msg
40+
end
41+
log_group.environment = details['env']
42+
log_group.server_name = details['server_name']
43+
log_group.application_name = details['app_name']
44+
log_group.application_location = details['app_location']
45+
log_group.logger = 'Ruby logger'
46+
log_group.platform = 'ruby'
47+
log_group
48+
end
49+
50+
def send_request log_group
51+
raise NotImplementedError
52+
end
53+
end
54+
end
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
module Stackify
2-
class UnixSocketClient
2+
class AgentClient
33

44
def initialize
5-
Stackify.internal_log :info, '[UnixSocketClient]: initialize()'
5+
Stackify.internal_log :info, '[AgentClient]: initialize()'
66
@@errors_governor = Stackify::ErrorsGovernor.new
7-
@@sender = Stackify::UnixSocketSender.new
7+
case Stackify.configuration.transport
8+
when Stackify::UNIX_SOCKET
9+
@@sender = Stackify::UnixSocketSender.new
10+
when Stackify::AGENT_HTTP
11+
@@sender = Stackify::AgentHTTPSender.new
12+
end
813
end
914

1015
def log level, msg, call_trace, task
@@ -22,11 +27,11 @@ def log_exception level= :error, ex, task
2227
worker.async_perform ScheduleDelay.new, task
2328
else
2429
Stackify.internal_log :warn,
25-
"UnixSocketClient: logging of exception with message \"#{ex.message}\" is skipped - flood_limit is exceeded"
30+
"AgentClient: logging of exception with message \"#{ex.message}\" is skipped - flood_limit is exceeded"
2631
end
2732
end
2833
else
29-
Stackify.log_internal_error 'UnixSocketClient: log_exception should get StackifiedError object'
34+
Stackify.log_internal_error 'AgentClient: log_exception should get StackifiedError object'
3035
end
3136
end
3237

lib/stackify/agent_http_sender.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
require 'uri'
2+
require 'faraday'
3+
require 'ostruct'
4+
5+
#
6+
# This class will handle the sending of protobuf message to agent using http request
7+
#
8+
module Stackify
9+
class AgentHTTPSender < AgentBaseSender
10+
11+
HEADERS = {
12+
'Content-Type' => 'application/x-protobuf'
13+
}
14+
15+
# send_request() This function will post an http request
16+
# @msgs {Object} Protobuf message
17+
# return {Object} Return an object {status, message}
18+
def send_request log_group
19+
begin
20+
# Convert data into binary and send it to agent
21+
message = Stackify::LogGroup.encode(log_group)
22+
conn = Faraday.new(proxy: Stackify.configuration.proxy)
23+
@response = conn.post do |req|
24+
req.url URI(Stackify.configuration.http_endpoint + Stackify.configuration.agent_log_url)
25+
req.headers = HEADERS
26+
req.body = message
27+
end
28+
if @response.try(:status) == 200
29+
Stackify.internal_log :debug, "[AgentHTTPSender]: Successfully send message via unix domain socket."
30+
return OpenStruct.new({status: 200, msg: 'OK'})
31+
else
32+
Stackify.internal_log :debug, "[AgentHTTPSender] Sending failed."
33+
return OpenStruct.new({status: 500, msg: 'Not OK'})
34+
end
35+
rescue => exception
36+
Stackify.log_internal_error "[AgentHTTPSender] send_logs() Error: #{exception}"
37+
return OpenStruct.new({status: 500, msg: exception})
38+
end
39+
end
40+
end
41+
end

lib/stackify/msgs_queue.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def add_msg msg
5252
Stackify::Utils.do_only_if_authorized_and_mode_is_on Stackify::MODES[:logging] do
5353
old_push(msg)
5454
end
55-
when Stackify::UNIX_SOCKET
55+
when Stackify::UNIX_SOCKET, Stackify::AGENT_HTTP
5656
old_push(msg)
5757
end
5858
end

lib/stackify/transport_selector.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ def initialize type
99
Stackify::Utils.do_only_if_authorized_and_mode_is_on Stackify::MODES[:logging] do
1010
@transport = Stackify::LogsSender.new
1111
end
12-
when Stackify::UNIX_SOCKET
13-
@transport = Stackify::UnixSocketClient.new
12+
when Stackify::UNIX_SOCKET, Stackify::AGENT_HTTP
13+
@transport = Stackify::AgentClient.new
1414
end
1515
end
1616
end
17-
end
17+
end

lib/stackify/unix_socket_sender.rb

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,7 @@
55
# This class will handle the sending of protobuf message to unix domain socket
66
#
77
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
8+
class UnixSocketSender < AgentBaseSender
529

5310
# send_request() This function will send http request via unix domain socket
5411
# @msgs {Object} Protobuf message
@@ -58,7 +15,7 @@ def send_request log_group
5815
# Convert data into binary and send it to unix domain socket
5916
message = Stackify::LogGroup.encode(log_group)
6017
client = NetX::HTTPUnix.new('unix://' + Stackify.configuration.unix_socket_path)
61-
req = Net::HTTP::Post.new(Stackify.configuration.unix_socket_url)
18+
req = Net::HTTP::Post.new(Stackify.configuration.agent_log_url)
6219
req.set_content_type('application/x-protobuf')
6320
req.body = message
6421
response = client.request(req)

lib/stackify/utils/configuration.rb

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ module Stackify
33
class Configuration
44

55
attr_accessor :api_key, :app_name, :app_location, :env, :log_level, :logger,
6-
:proxy, :mode, :base_api_url, :api_enabled, :transport, :errors
6+
:proxy, :mode, :base_api_url, :api_enabled, :transport, :errors, :http_endpoint
77

8-
attr_reader :send_interval, :flood_limit, :queue_max_size, :unix_socket_path, :unix_socket_url
8+
attr_reader :send_interval, :flood_limit, :queue_max_size, :agent_log_url, :unix_socket_path, :http_endpoint
99

1010
def initialize
1111
@base_api_url = 'https://api.stackify.com'
1212
@errors = []
1313
@app_name = ''
1414
@api_key = ''
15-
@transport = 'default'
15+
@transport = get_env 'STACKIFY_TRANSPORT', 'default'
1616
@env = :production
1717
@flood_limit = 100
1818
@queue_max_size = 10000
@@ -22,23 +22,32 @@ def initialize
2222
@mode = MODES[:both]
2323
@logger = Logger.new(STDOUT)
2424
@logger.level = Logger::UNKNOWN
25+
@agent_log_url = '/log'
2526
@unix_socket_path = '/usr/local/stackify/stackify.sock'
26-
@unix_socket_url = '/log'
27+
@http_endpoint = get_env 'STACKIFY_TRANSPORT_HTTP_ENDPOINT', 'https://localhost:10601'
28+
end
29+
30+
def get_env env_key, default
31+
value = default
32+
if ENV.keys.include? env_key
33+
value = ENV[env_key]
34+
end
35+
return value
2736
end
2837

2938
def is_valid?
3039
case Stackify.configuration.transport
3140
when Stackify::DEFAULT
3241
validate_default_transport
33-
when Stackify::UNIX_SOCKET
34-
validate_unix_domain_socket_transport
42+
when Stackify::UNIX_SOCKET, Stackify::AGENT_HTTP
43+
validate_agent_transport
3544
end
3645
@errors.empty?
3746
end
3847

3948
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.'
49+
return true if ['agent_socket', 'agent_http', 'default'].include? @transport
50+
@errors << 'Transport should be one of these values: [agent_socket, agent_http, default]. Should be a String.'
4251
end
4352

4453
private
@@ -60,9 +69,9 @@ def validate_default_transport
6069
validate_mode_type
6170
end
6271

63-
# Perform validation if transport type is agent_socket
72+
# Perform validation if transport type is agent_socket or agent_http
6473
# Required parameters are: env, app_name, log_level
65-
def validate_unix_domain_socket_transport
74+
def validate_agent_transport
6675
validate_env &&
6776
validate_transport_type &&
6877
validate_app_name &&

0 commit comments

Comments
 (0)