stackify-api-ruby 1.2.4 → 1.3.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +8 -1
- data/Gemfile.lock +42 -4
- data/README.md +17 -0
- data/lib/core_ext/core_ext.rb +0 -1
- data/lib/stackify-api-ruby.rb +6 -4
- data/lib/stackify/agent_base_sender.rb +18 -19
- data/lib/stackify/agent_client.rb +5 -5
- data/lib/stackify/agent_http_sender.rb +4 -6
- data/lib/stackify/authorization/authorizable.rb +5 -1
- data/lib/stackify/engine.rb +47 -0
- data/lib/stackify/error.rb +12 -3
- data/lib/stackify/logger_client.rb +27 -1
- data/lib/stackify/logger_proxy.rb +6 -4
- data/lib/stackify/metrics/metrics_client.rb +3 -3
- data/lib/stackify/rum.rb +72 -0
- data/lib/stackify/unix_socket_sender.rb +4 -6
- data/lib/stackify/utils/backtrace.rb +2 -1
- data/lib/stackify/utils/configuration.rb +54 -2
- data/lib/stackify/utils/methods.rb +26 -1
- data/lib/stackify/version.rb +1 -1
- data/lib/stackify/workers/logs_sender_worker.rb +8 -0
- data/spec/rum_spec.rb +291 -0
- data/spec/spec_helper.rb +9 -0
- data/stackify-api-ruby.gemspec +6 -1
- metadata +14 -12
- data/lib/core_ext/fixnum.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae96dffa800668cd0f8ab55fc62232c43951fbe5bf9700992698ece32bbbf006
|
4
|
+
data.tar.gz: 7e44e75717ecb342cdb632766708bb765793df1a92b534e689d59079c43d2bbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 032502e0aff449fa9ad239f282751ee0699cffcca713f14dff414eaac255cbabba348bcbabc5f5800be8aadecd787c1a7ba9d92620a86cb41ee7f579a1f6d56b
|
7
|
+
data.tar.gz: 8e93149a91583a7f9accc6d6ba1e87767ea8daa96049fc25941b89b27f4a1c459e4d6cce050126306b8097d979b993b5ddfe0c984191b7f503a6bc3af50948a3
|
data/Gemfile
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
|
1
|
+
group :test do
|
2
|
+
if ENV['STACKIFY_RUBY_TEST']
|
3
|
+
gem 'stackify-ruby-apm', '~> 1.15', source: ENV['STACKIFY_RUBY_TEST_REPO']
|
4
|
+
else
|
5
|
+
gem 'stackify-ruby-apm', '~> 1.15'
|
6
|
+
end
|
7
|
+
end
|
2
8
|
|
9
|
+
source 'https://rubygems.org'
|
3
10
|
# Specify your gem's dependencies in stackify.gemspec
|
4
11
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,24 +1,62 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
stackify-api-ruby (1.
|
4
|
+
stackify-api-ruby (1.3.0.beta1)
|
5
5
|
faraday (~> 0.8)
|
6
|
+
net_http_unix (~> 0.2)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
10
|
-
|
11
|
+
concurrent-ruby (1.1.9)
|
12
|
+
diff-lcs (1.4.4)
|
13
|
+
et-orbi (1.2.4)
|
14
|
+
tzinfo
|
15
|
+
faraday (0.17.4)
|
11
16
|
multipart-post (>= 1.2, < 3)
|
12
|
-
|
17
|
+
fugit (1.5.0)
|
18
|
+
et-orbi (~> 1.1, >= 1.1.8)
|
19
|
+
raabro (~> 1.4)
|
20
|
+
multipart-post (2.1.1)
|
21
|
+
net_http_unix (0.2.2)
|
22
|
+
raabro (1.4.0)
|
13
23
|
rake (0.9.6)
|
24
|
+
rspec (3.10.0)
|
25
|
+
rspec-core (~> 3.10.0)
|
26
|
+
rspec-expectations (~> 3.10.0)
|
27
|
+
rspec-mocks (~> 3.10.0)
|
28
|
+
rspec-core (3.10.1)
|
29
|
+
rspec-support (~> 3.10.0)
|
30
|
+
rspec-expectations (3.10.1)
|
31
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
32
|
+
rspec-support (~> 3.10.0)
|
33
|
+
rspec-mocks (3.10.2)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.10.0)
|
36
|
+
rspec-support (3.10.2)
|
37
|
+
rufus-scheduler (3.8.0)
|
38
|
+
fugit (~> 1.1, >= 1.1.6)
|
39
|
+
stackify-ruby-apm (1.15.1)
|
40
|
+
concurrent-ruby (~> 1.0)
|
41
|
+
faraday (~> 0.8)
|
42
|
+
net_http_unix (~> 0.2)
|
43
|
+
rufus-scheduler (~> 3.0)
|
44
|
+
tzinfo (2.0.4)
|
45
|
+
concurrent-ruby (~> 1.0)
|
46
|
+
tzinfo-data (1.2021.1)
|
47
|
+
tzinfo (>= 1.0.0)
|
14
48
|
|
15
49
|
PLATFORMS
|
16
50
|
ruby
|
51
|
+
x86-mingw32
|
17
52
|
|
18
53
|
DEPENDENCIES
|
19
54
|
bundler (~> 1.6)
|
20
55
|
rake (~> 0)
|
56
|
+
rspec (~> 3.0)
|
21
57
|
stackify-api-ruby!
|
58
|
+
stackify-ruby-apm (~> 1.15)
|
59
|
+
tzinfo-data
|
22
60
|
|
23
61
|
BUNDLED WITH
|
24
|
-
1.17.
|
62
|
+
1.17.13
|
data/README.md
CHANGED
@@ -124,6 +124,23 @@ We can configure every metric with settings:
|
|
124
124
|
|
125
125
|
Note, "autoreport_last_value_if_nothing_reported" property has influence only on "average" metric.
|
126
126
|
|
127
|
+
### **Real User Monitoring (RUM)**
|
128
|
+
|
129
|
+
Real user monitoring injects a script tag containing the [RUM JS](https://stackify.com/retrace-real-user-monitoring/) that is responsible for capturing information about the http requests on the browser. This approach is manual and needs to be configured.
|
130
|
+
|
131
|
+
#### RUM - Setup
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
# Configuration - Standard API
|
135
|
+
Stackify.setup do |config|
|
136
|
+
...
|
137
|
+
config.rum_key = "YourRumKey"
|
138
|
+
end
|
139
|
+
|
140
|
+
# Use this to apply on views
|
141
|
+
Stackify.rum.insert_rum_script
|
142
|
+
```
|
143
|
+
|
127
144
|
## Troubleshooting
|
128
145
|
|
129
146
|
If there are problems, you can enable internal logging of the stackify-api-ruby project. Uncomment out the config.logger and config.logger.level lines in the 'config/initializers/stackify.rb' file:
|
data/lib/core_ext/core_ext.rb
CHANGED
data/lib/stackify-api-ruby.rb
CHANGED
@@ -2,8 +2,6 @@ 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
6
|
module Stackify
|
9
7
|
|
@@ -14,7 +12,6 @@ module Stackify
|
|
14
12
|
|
15
13
|
autoload :Backtrace, 'stackify/utils/backtrace'
|
16
14
|
autoload :MsgObject, 'stackify/utils/msg_object'
|
17
|
-
autoload :ProtobufLogObject, 'stackify/utils/protobuf_log_object'
|
18
15
|
autoload :Configuration, 'stackify/utils/configuration'
|
19
16
|
autoload :HttpClient, 'stackify/http_client'
|
20
17
|
autoload :Authorizable, 'stackify/authorization/authorizable'
|
@@ -40,6 +37,7 @@ module Stackify
|
|
40
37
|
autoload :StringException, 'stackify/error'
|
41
38
|
autoload :ErrorsGovernor, 'stackify/errors_governor'
|
42
39
|
autoload :Metrics, 'stackify/metrics/metrics'
|
40
|
+
autoload :Rum, 'stackify/rum'
|
43
41
|
|
44
42
|
include Authorizable
|
45
43
|
|
@@ -51,6 +49,10 @@ module Stackify
|
|
51
49
|
@config ||= Stackify::Configuration.new
|
52
50
|
end
|
53
51
|
|
52
|
+
def rum
|
53
|
+
@rum ||= Stackify::Rum.new(configuration)
|
54
|
+
end
|
55
|
+
|
54
56
|
def setup
|
55
57
|
@workers = []
|
56
58
|
yield(configuration) if block_given?
|
@@ -123,7 +125,7 @@ module Stackify
|
|
123
125
|
|
124
126
|
def run
|
125
127
|
Stackify::Utils.is_api_enabled
|
126
|
-
Stackify.internal_log :info, "Stackify.run() transportType
|
128
|
+
Stackify.internal_log :info, "Stackify.run() transportType: #{Stackify.configuration.transport} | API version: #{Stackify::VERSION} | Ruby version: #{RUBY_VERSION}"
|
127
129
|
if Stackify.configuration.api_enabled
|
128
130
|
if Stackify.is_valid?
|
129
131
|
# check transport types
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# This class will handle the sending of
|
2
|
+
# This class will handle the sending of log group message to agent
|
3
3
|
#
|
4
4
|
module Stackify
|
5
5
|
class AgentBaseSender < Worker
|
@@ -23,28 +23,27 @@ module Stackify
|
|
23
23
|
def send_logs_task attempts = nil, msgs
|
24
24
|
properties[:attempts] = attempts if attempts
|
25
25
|
Stackify::ScheduleTask.new properties do
|
26
|
-
data =
|
26
|
+
data = gather_and_pack_data(msgs).to_json
|
27
27
|
send_request data
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
log_group
|
31
|
+
def gather_and_pack_data msgs
|
32
|
+
details = Stackify::EnvDetails.instance.auth_info
|
33
|
+
{
|
34
|
+
'CDID' => details['DeviceID'],
|
35
|
+
'CDAppID' => details['DeviceAppID'],
|
36
|
+
'Logger' => 'Rails logger',
|
37
|
+
'AppName' => details['AppName'],
|
38
|
+
'AppNameID' => details['AppNameID'],
|
39
|
+
'Env' => details['Env'],
|
40
|
+
'EnvID' => details['EnvID'],
|
41
|
+
'AppEnvID' => details['AppEnvID'],
|
42
|
+
'ServerName' => details['DeviceName'],
|
43
|
+
'Msgs' => msgs,
|
44
|
+
'AppLoc' => details['AppLocation'],
|
45
|
+
'Platform' => 'Ruby'
|
46
|
+
}
|
48
47
|
end
|
49
48
|
|
50
49
|
def send_request log_group
|
@@ -36,11 +36,11 @@ module Stackify
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def has_error msg
|
39
|
-
!msg.
|
39
|
+
!msg['Ex'].nil?
|
40
40
|
end
|
41
41
|
|
42
42
|
def get_epoch msg
|
43
|
-
msg
|
43
|
+
msg['EpochMs']
|
44
44
|
end
|
45
45
|
|
46
46
|
def send_logs msgs, attempts = 3
|
@@ -59,16 +59,16 @@ module Stackify
|
|
59
59
|
e
|
60
60
|
end
|
61
61
|
ex = StackifiedError.new(ex, binding())
|
62
|
-
Stackify.msgs_queue << Stackify::
|
62
|
+
Stackify.msgs_queue << Stackify::MsgObject.new(level, ex.message, caller[0], trans_id, log_uuid, ex).to_h
|
63
63
|
else
|
64
|
-
Stackify.msgs_queue << Stackify::
|
64
|
+
Stackify.msgs_queue << Stackify::MsgObject.new(level, msg, caller[0], trans_id, log_uuid).to_h
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
69
|
def log_exception_task level, ex, trans_id=nil, log_uuid=nil
|
70
70
|
Stackify::ScheduleTask.new ({limit: 1}) do
|
71
|
-
Stackify.msgs_queue << Stackify::
|
71
|
+
Stackify.msgs_queue << Stackify::MsgObject.new(level, ex.message, caller[0], trans_id, log_uuid, ex).to_h
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -3,27 +3,25 @@ require 'faraday'
|
|
3
3
|
require 'ostruct'
|
4
4
|
|
5
5
|
#
|
6
|
-
# This class will handle the sending of
|
6
|
+
# This class will handle the sending of log messages to agent using http request
|
7
7
|
#
|
8
8
|
module Stackify
|
9
9
|
class AgentHTTPSender < AgentBaseSender
|
10
10
|
|
11
11
|
HEADERS = {
|
12
|
-
'Content-Type' => 'application/
|
12
|
+
'Content-Type' => 'application/json'
|
13
13
|
}
|
14
14
|
|
15
15
|
# send_request() This function will post an http request
|
16
|
-
# @msgs {Object}
|
16
|
+
# @msgs {Object} log group message
|
17
17
|
# return {Object} Return an object {status, message}
|
18
18
|
def send_request log_group
|
19
19
|
begin
|
20
|
-
# Convert data into binary and send it to agent
|
21
|
-
message = Stackify::LogGroup.encode(log_group)
|
22
20
|
conn = Faraday.new(proxy: Stackify.configuration.proxy, ssl: { verify: false })
|
23
21
|
@response = conn.post do |req|
|
24
22
|
req.url URI(Stackify.configuration.http_endpoint + Stackify.configuration.agent_log_url)
|
25
23
|
req.headers = HEADERS
|
26
|
-
req.body =
|
24
|
+
req.body = log_group
|
27
25
|
end
|
28
26
|
if @response.try(:status) == 200
|
29
27
|
Stackify.internal_log :debug, "[AgentHTTPSender]: Successfully send message via http request."
|
@@ -11,7 +11,11 @@ module Stackify::Authorizable
|
|
11
11
|
@@auth_client = nil
|
12
12
|
|
13
13
|
def authorize attempts=3
|
14
|
-
|
14
|
+
# Check if the ruby version is 2.0 we get the Rails info properties such as
|
15
|
+
# <Application root: e.g., /home/user/rails_app> which is required in authorization
|
16
|
+
if Gem::Version.new(RUBY_VERSION) <= Gem::Version.new('2.0')
|
17
|
+
Stackify::EnvDetails.instance.set_rails_info
|
18
|
+
end
|
15
19
|
@@auth_lock.synchronize do
|
16
20
|
return unless @@auth_client.nil?
|
17
21
|
@@auth_client = Stackify::Authorizable::AuthorizationClient.new
|
data/lib/stackify/engine.rb
CHANGED
@@ -4,7 +4,32 @@ module Stackify
|
|
4
4
|
|
5
5
|
if Rails.version > '3.1'
|
6
6
|
initializer 'Stackify set up of logger', group: :all do
|
7
|
+
if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('4.0')
|
8
|
+
# check if the client app is using the ActiveSupport::Logger
|
9
|
+
is_activesupport_logger = ::Rails.logger.is_a?(ActiveSupport::Logger)
|
10
|
+
elsif Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('3.0')
|
11
|
+
Stackify::Utils.check_buffered_logger
|
12
|
+
end
|
13
|
+
|
14
|
+
# Check if the log output is STDOUT
|
15
|
+
Stackify::Utils.check_log_output
|
16
|
+
|
17
|
+
# Proxy the client Rails logger and write logs to its default log_path.
|
18
|
+
# At the same time, we send the log messages to the LoggerClient.
|
7
19
|
::Rails.logger = ::Stackify::LoggerProxy.new ::Rails.logger
|
20
|
+
|
21
|
+
if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('6.0')
|
22
|
+
set_console_logs ::Rails.logger
|
23
|
+
elsif Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('4.0')
|
24
|
+
if is_activesupport_logger && Stackify.configuration.stdout_output
|
25
|
+
set_console_logs ::Rails.logger
|
26
|
+
end
|
27
|
+
# Another checking if the client app is using the default logger and not STDOUT
|
28
|
+
if Stackify.configuration.stdout_output == false
|
29
|
+
set_console_logs ::Rails.logger
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
8
33
|
Stackify.run
|
9
34
|
end
|
10
35
|
|
@@ -14,6 +39,28 @@ module Stackify
|
|
14
39
|
end
|
15
40
|
end
|
16
41
|
|
42
|
+
def set_console_logs new_logger
|
43
|
+
if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('6.0')
|
44
|
+
ActiveSupport.on_load(:action_controller_base) do
|
45
|
+
logger = new_logger
|
46
|
+
end
|
47
|
+
ActiveSupport.on_load(:action_view) do
|
48
|
+
logger = new_logger
|
49
|
+
end
|
50
|
+
ActiveSupport.on_load(:active_record) do
|
51
|
+
logger = new_logger
|
52
|
+
end
|
53
|
+
else
|
54
|
+
# Handle the stdout logs from Action Controller
|
55
|
+
ActionController::Base.logger = new_logger
|
56
|
+
|
57
|
+
# Handle the stdout logs from Action View
|
58
|
+
ActionView::Base.logger = new_logger
|
59
|
+
|
60
|
+
# Handle the stdout logs from Active Record
|
61
|
+
ActiveRecord::Base.logger = new_logger
|
62
|
+
end
|
63
|
+
end
|
17
64
|
end
|
18
65
|
|
19
66
|
end
|
data/lib/stackify/error.rb
CHANGED
@@ -40,7 +40,7 @@ module Stackify
|
|
40
40
|
|
41
41
|
def to_h
|
42
42
|
env = Stackify::EnvDetails.instance
|
43
|
-
{
|
43
|
+
data = {
|
44
44
|
'OccurredEpochMillis' => Time.now.to_f*1000,
|
45
45
|
'Error' => {
|
46
46
|
'InnerError' => @exception.try(:cause),
|
@@ -52,11 +52,20 @@ module Stackify
|
|
52
52
|
'SourceMethod' => source_method,
|
53
53
|
},
|
54
54
|
'EnvironmentDetail' => env.auth_info,
|
55
|
-
'WebRequestDetail' => env.request_details.try{ |d| d.fetch('webrequest_details', '') },
|
56
|
-
'ServerVariables' => env.request_details.try{ |d| d.fetch('server_variables', '') },
|
57
55
|
'CustomerName' => 'Customer',
|
58
56
|
'UserName' => @context.fetch('user', '')
|
59
57
|
}
|
58
|
+
web_request_details = env.request_details.try{ |d| d.fetch('webrequest_details', '') }
|
59
|
+
if web_request_details.nil?
|
60
|
+
data['WebRequestDetail'] = web_request_details
|
61
|
+
end
|
62
|
+
|
63
|
+
server_variables = env.request_details.try{ |d| d.fetch('server_variables', '') }
|
64
|
+
if server_variables.nil?
|
65
|
+
data['ServerVariables'] = server_variables
|
66
|
+
end
|
67
|
+
|
68
|
+
data
|
60
69
|
end
|
61
70
|
|
62
71
|
end
|
@@ -12,7 +12,33 @@ module Stackify
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
# This function is responsible in displaying log messages based on the level criteria
|
16
|
+
# @param num_level [Integer] level of the clients Rails.logger
|
17
|
+
# @param level [String] level coming from array of levels(debug info warn error fatal unknown) that we are going to filter with num_level
|
18
|
+
# So we filter all logs from num_level up to this level
|
19
|
+
# @param msg [Integer] log messages
|
20
|
+
# @param call_trace [Object] return the current execution stack
|
21
|
+
def log num_level, level, msg, call_trace
|
22
|
+
display_log = true
|
23
|
+
log_appender = false
|
24
|
+
buffer_log = false
|
25
|
+
if defined? Rails
|
26
|
+
display_log = false if Stackify.configuration.stdout_output
|
27
|
+
log_appender = true if defined?(Logging)
|
28
|
+
buffer_log = true if Stackify.configuration.buffered_logger
|
29
|
+
unless buffer_log
|
30
|
+
if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('4.0')
|
31
|
+
if display_log && log_appender
|
32
|
+
puts msg if num_level <= Logger.const_get(level.upcase).to_i
|
33
|
+
elsif display_log && log_appender == false
|
34
|
+
puts msg if num_level <= Logger.const_get(level.upcase).to_i
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
else
|
39
|
+
puts msg if num_level <= Logger.const_get(level.upcase).to_i
|
40
|
+
end
|
41
|
+
|
16
42
|
return if @@transport.nil?
|
17
43
|
task = log_message_task level, msg, call_trace
|
18
44
|
@@transport.log level, msg, call_trace, task
|
@@ -1,14 +1,16 @@
|
|
1
|
+
|
1
2
|
module Stackify
|
2
3
|
class LoggerProxy < Object
|
3
4
|
|
4
5
|
def initialize logger
|
5
|
-
|
6
|
-
|
6
|
+
rails_logger = logger
|
7
|
+
num_level = logger.level
|
8
|
+
@logger = rails_logger
|
7
9
|
%w(debug info warn error fatal unknown).each do |level|
|
8
10
|
stackify_logger = if level == 'debug'
|
9
|
-
-> (msg, caller) { Stackify.logger_client.log(level.downcase, msg, caller) unless msg.to_s.empty? }
|
11
|
+
-> (msg, caller) { Stackify.logger_client.log(num_level, level.downcase, msg, caller) unless msg.to_s.empty? }
|
10
12
|
else
|
11
|
-
-> (msg, caller) { Stackify.logger_client.log(level.downcase, msg, caller) }
|
13
|
+
-> (msg, caller) { Stackify.logger_client.log(num_level, level.downcase, msg, caller) }
|
12
14
|
end
|
13
15
|
LoggerProxy.class_eval do
|
14
16
|
define_method level.to_sym do |*args , &block|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Stackify::Metrics
|
2
2
|
class MetricsClient
|
3
|
-
|
3
|
+
TEN_MINUTES = 600
|
4
4
|
attr_reader :metrics_queue
|
5
5
|
|
6
6
|
def initialize
|
@@ -57,7 +57,7 @@ module Stackify::Metrics
|
|
57
57
|
|
58
58
|
def start_upload_metrics
|
59
59
|
current_time = Stackify::Utils.rounded_current_time
|
60
|
-
purge_older_than = current_time -
|
60
|
+
purge_older_than = current_time - TEN_MINUTES
|
61
61
|
#read everything up to the start of the current minute
|
62
62
|
read_queued_metrics_batch current_time
|
63
63
|
handle_zero_reports current_time
|
@@ -67,7 +67,7 @@ module Stackify::Metrics
|
|
67
67
|
if first_50_metrics.length > 0
|
68
68
|
#only getting metrics less than 10 minutes old to drop old data in case we get backed up
|
69
69
|
#they are removed from the @aggregated_metrics in the upload function upon success
|
70
|
-
upload_aggregates(first_50_metrics.select { |_key, aggr| aggr.occurred_utc > current_time -
|
70
|
+
upload_aggregates(first_50_metrics.select { |_key, aggr| aggr.occurred_utc > current_time - TEN_MINUTES })
|
71
71
|
end
|
72
72
|
@aggregate_metrics.delete_if { |_key, aggr| aggr.occurred_utc < purge_older_than }
|
73
73
|
end
|
data/lib/stackify/rum.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
$apmLoaded = false
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'stackify-ruby-apm'
|
5
|
+
$apmLoaded = true
|
6
|
+
rescue LoadError
|
7
|
+
end
|
8
|
+
|
9
|
+
module Stackify
|
10
|
+
class Rum
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
def insert_rum_script()
|
16
|
+
return StackifyRubyAPM.inject_rum_script if Rum.apm_loaded && defined?(StackifyRubyAPM) && StackifyRubyAPM.respond_to?(:inject_rum_script)
|
17
|
+
|
18
|
+
return '' unless @config
|
19
|
+
|
20
|
+
config = @config
|
21
|
+
|
22
|
+
return '' if config.rum_script_url.to_s.empty? || config.rum_key.to_s.empty?
|
23
|
+
|
24
|
+
transaction_id = get_transaction_id().to_s
|
25
|
+
return '' if transaction_id.empty?
|
26
|
+
|
27
|
+
reporting_url = get_reporting_url().to_s
|
28
|
+
return '' if reporting_url.empty?
|
29
|
+
|
30
|
+
environment_name = defined?(config.env) ? config.env.to_s : 'Development'
|
31
|
+
return '' if environment_name.empty?
|
32
|
+
|
33
|
+
application_name = defined?(config.app_name) ? config.app_name.to_s : ''
|
34
|
+
return '' if application_name.empty?
|
35
|
+
|
36
|
+
rum_settings = {
|
37
|
+
"ID" => transaction_id
|
38
|
+
}
|
39
|
+
|
40
|
+
if !environment_name.empty?
|
41
|
+
rum_settings["Env"] = Base64.strict_encode64(environment_name.encode('utf-8'))
|
42
|
+
end
|
43
|
+
|
44
|
+
if !application_name.empty?
|
45
|
+
rum_settings["Name"] = Base64.strict_encode64(application_name.strip.encode('utf-8'))
|
46
|
+
end
|
47
|
+
|
48
|
+
if !reporting_url.empty?
|
49
|
+
rum_settings["Trans"] = Base64.strict_encode64(reporting_url.encode('utf-8'))
|
50
|
+
end
|
51
|
+
|
52
|
+
rum_content = "<script type=\"text/javascript\">(window.StackifySettings || (window.StackifySettings = #{rum_settings.to_json}))</script><script src=\"#{config.rum_script_url}\" data-key=\"#{config.rum_key}\" async></script>"
|
53
|
+
if rum_content.respond_to?(:html_safe)
|
54
|
+
rum_content.html_safe
|
55
|
+
else
|
56
|
+
rum_content
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.apm_loaded
|
61
|
+
$apmLoaded
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_reporting_url
|
65
|
+
''
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_transaction_id
|
69
|
+
''
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -2,22 +2,20 @@ require 'net_http_unix'
|
|
2
2
|
require 'ostruct'
|
3
3
|
|
4
4
|
#
|
5
|
-
# This class will handle the sending of
|
5
|
+
# This class will handle the sending of log messages to unix domain socket
|
6
6
|
#
|
7
7
|
module Stackify
|
8
8
|
class UnixSocketSender < AgentBaseSender
|
9
9
|
|
10
10
|
# send_request() This function will send http request via unix domain socket
|
11
|
-
# @msgs {Object}
|
11
|
+
# @msgs {Object} log group message
|
12
12
|
# return {Object} Return an object {status, message}
|
13
13
|
def send_request log_group
|
14
14
|
begin
|
15
|
-
# Convert data into binary and send it to unix domain socket
|
16
|
-
message = Stackify::LogGroup.encode(log_group)
|
17
15
|
client = NetX::HTTPUnix.new('unix://' + Stackify.configuration.unix_socket_path)
|
18
16
|
req = Net::HTTP::Post.new(Stackify.configuration.agent_log_url)
|
19
|
-
req.set_content_type('application/
|
20
|
-
req.body =
|
17
|
+
req.set_content_type('application/json')
|
18
|
+
req.body = log_group
|
21
19
|
response = client.request(req)
|
22
20
|
Stackify.internal_log :debug, "[UnixSocketSender] status_code = #{response.code}"
|
23
21
|
if response.code.to_i == 200
|
@@ -3,6 +3,7 @@ module Stackify::Backtrace
|
|
3
3
|
ALL_TEXT_FROM_START_TO_FIRST_COLON_REGEXP = /\A([^:]+)/
|
4
4
|
NUMBER_BETWEEN_TWO_COLONS_REGEXP = /:(\d+):/
|
5
5
|
TEXT_AFTER_IN_BEFORE_END_REGEXP = /in\s`(\S+)'\z/
|
6
|
+
TEXT_AFTER_IN_BEFORE_END_REGEXP_ = /in\s(\S+)'\z/
|
6
7
|
|
7
8
|
def self.line_number backtrace_str
|
8
9
|
backtrace_str[NUMBER_BETWEEN_TWO_COLONS_REGEXP, 1]
|
@@ -10,7 +11,7 @@ module Stackify::Backtrace
|
|
10
11
|
|
11
12
|
def self.method_name backtrace_str
|
12
13
|
return nil unless backtrace_str
|
13
|
-
backtrace_str[TEXT_AFTER_IN_BEFORE_END_REGEXP, 1]
|
14
|
+
backtrace_str[TEXT_AFTER_IN_BEFORE_END_REGEXP, 1] || backtrace_str[TEXT_AFTER_IN_BEFORE_END_REGEXP_, 1]
|
14
15
|
end
|
15
16
|
|
16
17
|
def self.file_name backtrace_str
|
@@ -3,9 +3,10 @@ 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, :transport, :errors, :http_endpoint
|
6
|
+
:proxy, :mode, :base_api_url, :api_enabled, :transport, :errors, :http_endpoint, :stdout_output, :buffered_logger
|
7
7
|
|
8
|
-
attr_reader :send_interval, :flood_limit, :queue_max_size, :agent_log_url, :unix_socket_path, :http_endpoint
|
8
|
+
attr_reader :send_interval, :flood_limit, :queue_max_size, :agent_log_url, :unix_socket_path, :http_endpoint,
|
9
|
+
:rum_key, :rum_script_url
|
9
10
|
|
10
11
|
def initialize
|
11
12
|
@base_api_url = 'https://api.stackify.com'
|
@@ -25,6 +26,13 @@ module Stackify
|
|
25
26
|
@agent_log_url = '/log'
|
26
27
|
@unix_socket_path = '/usr/local/stackify/stackify.sock'
|
27
28
|
@http_endpoint = get_env 'STACKIFY_TRANSPORT_HTTP_ENDPOINT', 'https://localhost:10601'
|
29
|
+
@stdout_output = false
|
30
|
+
@buffered_logger = false
|
31
|
+
@default_rum_script_url = 'https://stckjs.stackify.com/stckjs.js'
|
32
|
+
@default_rum_key = ''
|
33
|
+
|
34
|
+
self.rum_key = get_env 'RETRACE_RUM_KEY', @default_rum_key
|
35
|
+
self.rum_script_url = get_env 'RETRACE_RUM_SCRIPT_URL', @default_rum_script_url
|
28
36
|
end
|
29
37
|
|
30
38
|
def get_env env_key, default
|
@@ -50,6 +58,28 @@ module Stackify
|
|
50
58
|
@errors << 'Transport should be one of these values: [agent_socket, agent_http, default]. Should be a String.'
|
51
59
|
end
|
52
60
|
|
61
|
+
def rum_script_url=(rum_script_url)
|
62
|
+
if rum_script_url.empty?
|
63
|
+
@rum_script_url = @default_rum_script_url
|
64
|
+
return
|
65
|
+
end
|
66
|
+
|
67
|
+
if validate_rum_script_url(rum_script_url)
|
68
|
+
@rum_script_url = rum_script_url
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def rum_key=(rum_key)
|
73
|
+
if rum_key.empty?
|
74
|
+
@rum_key = @default_rum_key
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
if validate_rum_key(rum_key)
|
79
|
+
@rum_key = rum_key
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
53
83
|
private
|
54
84
|
|
55
85
|
def validate_config_types
|
@@ -108,5 +138,27 @@ module Stackify
|
|
108
138
|
return true if MODES.has_value? @mode
|
109
139
|
@errors << 'Mode should be one of these values: [:both, :logging, :metrics]'
|
110
140
|
end
|
141
|
+
|
142
|
+
def validate_rum_script_url(rum_script_url)
|
143
|
+
result = false
|
144
|
+
if rum_script_url.is_a?(String) && !rum_script_url.empty?
|
145
|
+
result = rum_script_url =~ /^((((https?|ftps?|gopher|telnet|nntp):\/\/)|(mailto:|news:))(%[0-9A-Fa-f]{2}|[\-\(\)_\.!~*';\/?:@&=+$,A-Za-z0-9])+)([\)\.!';\/?:,][\[:blank:|:blank:\]])?$/
|
146
|
+
end
|
147
|
+
if !result
|
148
|
+
@errors << 'RUM Script URL is in invalid format.'
|
149
|
+
end
|
150
|
+
result
|
151
|
+
end
|
152
|
+
|
153
|
+
def validate_rum_key(rum_key)
|
154
|
+
result = false
|
155
|
+
if rum_key.is_a?(String) && !rum_key.empty?
|
156
|
+
result = rum_key =~ %r{^[A-Za-z0-9_-]+$}
|
157
|
+
end
|
158
|
+
if !result
|
159
|
+
@errors << 'RUM Key is in invalid format.'
|
160
|
+
end
|
161
|
+
result
|
162
|
+
end
|
111
163
|
end
|
112
164
|
end
|
@@ -46,4 +46,29 @@ module Stackify::Utils
|
|
46
46
|
'app_location' => Stackify.configuration.app_location || Dir.pwd
|
47
47
|
}
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
|
+
# Check if the app is running on rails and the logger output is using STDOUT
|
51
|
+
def self.check_log_output
|
52
|
+
if defined? Rails
|
53
|
+
if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('5.0')
|
54
|
+
Stackify.configuration.stdout_output = ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT)
|
55
|
+
else
|
56
|
+
Stackify.configuration.stdout_output = self.logger_stdout
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.logger_stdout
|
62
|
+
logdev = ::Rails.logger.instance_variable_get(:@logdev)
|
63
|
+
logger_source = logdev.dev if logdev.respond_to?(:dev)
|
64
|
+
sources = [$stdout]
|
65
|
+
found = sources.any? { |source| source == logger_source }
|
66
|
+
end
|
67
|
+
|
68
|
+
# Check if the rails version 3 and it's using the buffered logger
|
69
|
+
def self.check_buffered_logger
|
70
|
+
is_buffered_logger = false
|
71
|
+
is_buffered_logger = true if ::Rails.logger.is_a?(ActiveSupport::BufferedLogger)
|
72
|
+
Stackify.configuration.buffered_logger = is_buffered_logger
|
73
|
+
end
|
74
|
+
end
|
data/lib/stackify/version.rb
CHANGED
@@ -3,6 +3,14 @@ module Stackify
|
|
3
3
|
|
4
4
|
def initialize name = 'LogsSender worker'
|
5
5
|
super
|
6
|
+
case Stackify.configuration.transport
|
7
|
+
when Stackify::DEFAULT
|
8
|
+
name = 'LogsSender worker'
|
9
|
+
when Stackify::UNIX_SOCKET
|
10
|
+
name = 'UnixSocketSender worker'
|
11
|
+
when Stackify::AGENT_HTTP
|
12
|
+
name = 'AgentHTTPSender worker'
|
13
|
+
end
|
6
14
|
@name = name
|
7
15
|
@name += " ##{self.id}"
|
8
16
|
@type = :logs_send
|
data/spec/rum_spec.rb
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'stackify-api-ruby'
|
3
|
+
|
4
|
+
module Stackify
|
5
|
+
RSpec.describe 'Rum - APM not loaded - Normal' do
|
6
|
+
it 'returns rum script with complete information from ENV' do
|
7
|
+
ENV['RETRACE_RUM_KEY'] = 'test-key'
|
8
|
+
ENV['RETRACE_RUM_SCRIPT_URL'] = 'https://test.com/test.js'
|
9
|
+
|
10
|
+
config = Stackify::Configuration.new
|
11
|
+
config.app_name = 'test'
|
12
|
+
config.env = 'test-env'
|
13
|
+
|
14
|
+
rum = Stackify::Rum.new(config)
|
15
|
+
reporting_url = "test reporting url"
|
16
|
+
transaction_id = "123-id"
|
17
|
+
rum_script_url = 'https://test.com/test.js'
|
18
|
+
|
19
|
+
rum_settings = {
|
20
|
+
"ID" => '123-id',
|
21
|
+
"Env" => Base64.strict_encode64('test-env'.encode('utf-8')),
|
22
|
+
"Name" => Base64.strict_encode64('test'.strip.encode('utf-8')), # TODO: Add helper function
|
23
|
+
"Trans" => Base64.strict_encode64('test reporting url'.encode('utf-8'))
|
24
|
+
}
|
25
|
+
|
26
|
+
expected_rum_script = "<script type=\"text/javascript\">(window.StackifySettings || (window.StackifySettings = #{rum_settings.to_json()}))<\/script><script src=\"#{rum_script_url}\" data-key=\"#{config.rum_key}\" async></script>"
|
27
|
+
|
28
|
+
allow(rum).to receive(:get_reporting_url).and_return(reporting_url)
|
29
|
+
allow(rum).to receive(:get_transaction_id).and_return(transaction_id)
|
30
|
+
allow(Rum).to receive(:apm_loaded).and_return(false)
|
31
|
+
|
32
|
+
rum_script = rum.insert_rum_script
|
33
|
+
|
34
|
+
expect(rum.get_reporting_url).to eq reporting_url
|
35
|
+
expect(rum.get_transaction_id).to eq transaction_id
|
36
|
+
expect(rum_script.to_s).not_to be_empty
|
37
|
+
expect(rum_script).to eq expected_rum_script
|
38
|
+
|
39
|
+
ENV.delete('RETRACE_RUM_KEY')
|
40
|
+
ENV.delete('RETRACE_RUM_SCRIPT_URL')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns rum script with complete information from Config' do
|
44
|
+
config = Stackify::Configuration.new
|
45
|
+
config.app_name = 'test'
|
46
|
+
config.env = 'test-env'
|
47
|
+
config.rum_script_url = 'https://test.com/test.js'
|
48
|
+
config.rum_key = 'asd'
|
49
|
+
|
50
|
+
rum = Stackify::Rum.new(config)
|
51
|
+
reporting_url = "test reporting url"
|
52
|
+
transaction_id = "123-id"
|
53
|
+
rum_script_url = 'https://test.com/test.js'
|
54
|
+
rum_key = 'asd'
|
55
|
+
|
56
|
+
rum_settings = {
|
57
|
+
"ID" => '123-id',
|
58
|
+
"Env" => Base64.strict_encode64('test-env'.encode('utf-8')),
|
59
|
+
"Name" => Base64.strict_encode64('test'.strip.encode('utf-8')), # TODO: Add helper function
|
60
|
+
"Trans" => Base64.strict_encode64('test reporting url'.encode('utf-8'))
|
61
|
+
}
|
62
|
+
|
63
|
+
expected_rum_script = "<script type=\"text/javascript\">(window.StackifySettings || (window.StackifySettings = #{rum_settings.to_json()}))<\/script><script src=\"#{rum_script_url}\" data-key=\"#{rum_key}\" async></script>"
|
64
|
+
|
65
|
+
allow(rum).to receive(:get_reporting_url).and_return(reporting_url)
|
66
|
+
allow(rum).to receive(:get_transaction_id).and_return(transaction_id)
|
67
|
+
allow(Rum).to receive(:apm_loaded).and_return(false)
|
68
|
+
|
69
|
+
rum_script = rum.insert_rum_script
|
70
|
+
|
71
|
+
expect(rum.get_reporting_url).to eq reporting_url
|
72
|
+
expect(rum.get_transaction_id).to eq transaction_id
|
73
|
+
expect(rum_script.to_s).not_to be_empty
|
74
|
+
expect(rum_script).to eq expected_rum_script
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
RSpec.describe 'Rum - APM not loaded - Invalid' do
|
79
|
+
it 'returns rum script with invalid rum script url from Config' do
|
80
|
+
config = Stackify::Configuration.new
|
81
|
+
config.app_name = 'test'
|
82
|
+
config.env = 'test-env'
|
83
|
+
config.rum_script_url = 'test.js'
|
84
|
+
config.rum_key = 'asd'
|
85
|
+
|
86
|
+
rum = Stackify::Rum.new(config)
|
87
|
+
reporting_url = "test reporting url"
|
88
|
+
transaction_id = "123-id"
|
89
|
+
rum_script_url = 'https://stckjs.stackify.com/stckjs.js'
|
90
|
+
rum_key = 'asd'
|
91
|
+
|
92
|
+
rum_settings = {
|
93
|
+
"ID" => '123-id',
|
94
|
+
"Env" => Base64.strict_encode64('test-env'.encode('utf-8')),
|
95
|
+
"Name" => Base64.strict_encode64('test'.strip.encode('utf-8')), # TODO: Add helper function
|
96
|
+
"Trans" => Base64.strict_encode64('test reporting url'.encode('utf-8'))
|
97
|
+
}
|
98
|
+
|
99
|
+
expected_rum_script = "<script type=\"text/javascript\">(window.StackifySettings || (window.StackifySettings = #{rum_settings.to_json()}))<\/script><script src=\"#{rum_script_url}\" data-key=\"#{rum_key}\" async></script>"
|
100
|
+
|
101
|
+
allow(rum).to receive(:get_reporting_url).and_return(reporting_url)
|
102
|
+
allow(rum).to receive(:get_transaction_id).and_return(transaction_id)
|
103
|
+
allow(Rum).to receive(:apm_loaded).and_return(false)
|
104
|
+
|
105
|
+
rum_script = rum.insert_rum_script
|
106
|
+
|
107
|
+
expect(rum.get_reporting_url).to eq reporting_url
|
108
|
+
expect(rum.get_transaction_id).to eq transaction_id
|
109
|
+
expect(rum_script.to_s).not_to be_empty
|
110
|
+
expect(rum_script).to eq expected_rum_script
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'returns rum script with invalid rum key from Config' do
|
114
|
+
config = Stackify::Configuration.new
|
115
|
+
config.app_name = 'test'
|
116
|
+
config.env = 'test-env'
|
117
|
+
config.rum_script_url = 'test.js'
|
118
|
+
config.rum_key = '`asd'
|
119
|
+
|
120
|
+
rum = Stackify::Rum.new(config)
|
121
|
+
reporting_url = "test reporting url"
|
122
|
+
transaction_id = "123-id"
|
123
|
+
rum_script_url = 'https://stckjs.stackify.com/stckjs.js'
|
124
|
+
rum_key = 'asd'
|
125
|
+
|
126
|
+
rum_settings = {
|
127
|
+
"ID" => '123-id',
|
128
|
+
"Env" => Base64.strict_encode64('test-env'.encode('utf-8')),
|
129
|
+
"Name" => Base64.strict_encode64('test'.strip.encode('utf-8')), # TODO: Add helper function
|
130
|
+
"Trans" => Base64.strict_encode64('test reporting url'.encode('utf-8'))
|
131
|
+
}
|
132
|
+
|
133
|
+
expected_rum_script = "<script type=\"text/javascript\">(window.StackifySettings || (window.StackifySettings = #{rum_settings.to_json()}))<\/script><script src=\"#{rum_script_url}\" data-key=\"#{rum_key}\" async></script>"
|
134
|
+
|
135
|
+
allow(rum).to receive(:get_reporting_url).and_return(reporting_url)
|
136
|
+
allow(rum).to receive(:get_transaction_id).and_return(transaction_id)
|
137
|
+
allow(Rum).to receive(:apm_loaded).and_return(false)
|
138
|
+
|
139
|
+
rum_script = rum.insert_rum_script
|
140
|
+
|
141
|
+
expect(rum.get_reporting_url).to eq reporting_url
|
142
|
+
expect(rum.get_transaction_id).to eq transaction_id
|
143
|
+
expect(rum_script.to_s).to be_empty
|
144
|
+
expect(rum_script).not_to eq expected_rum_script
|
145
|
+
expect(config.rum_key).to be_empty
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'returns rum script with no app name' do
|
149
|
+
config = Stackify::Configuration.new
|
150
|
+
config.app_name = ''
|
151
|
+
config.env = 'test-env'
|
152
|
+
config.rum_script_url = 'test.js'
|
153
|
+
config.rum_key = '`asd'
|
154
|
+
|
155
|
+
rum = Stackify::Rum.new(config)
|
156
|
+
|
157
|
+
reporting_url = "test reporting url"
|
158
|
+
transaction_id = "123-id"
|
159
|
+
|
160
|
+
allow(rum).to receive(:get_reporting_url).and_return(reporting_url)
|
161
|
+
allow(rum).to receive(:get_transaction_id).and_return(transaction_id)
|
162
|
+
allow(Rum).to receive(:apm_loaded).and_return(false)
|
163
|
+
|
164
|
+
rum_script = rum.insert_rum_script
|
165
|
+
|
166
|
+
expect(rum.get_reporting_url).to eq reporting_url
|
167
|
+
expect(rum.get_transaction_id).to eq transaction_id
|
168
|
+
expect(rum_script.to_s).to be_empty
|
169
|
+
expect(config.rum_key).to be_empty
|
170
|
+
expect(config.app_name).to be_empty
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'returns rum script with no env' do
|
174
|
+
config = Stackify::Configuration.new
|
175
|
+
config.app_name = 'test'
|
176
|
+
config.rum_script_url = 'test.js'
|
177
|
+
config.rum_key = 'asd'
|
178
|
+
|
179
|
+
rum = Stackify::Rum.new(config)
|
180
|
+
reporting_url = "test reporting url"
|
181
|
+
transaction_id = "123-id"
|
182
|
+
rum_script_url = 'https://stckjs.stackify.com/stckjs.js'
|
183
|
+
rum_key = 'asd'
|
184
|
+
|
185
|
+
rum_settings = {
|
186
|
+
"ID" => '123-id',
|
187
|
+
"Env" => Base64.strict_encode64('production'.encode('utf-8')),
|
188
|
+
"Name" => Base64.strict_encode64('test'.strip.encode('utf-8')), # TODO: Add helper function
|
189
|
+
"Trans" => Base64.strict_encode64('test reporting url'.encode('utf-8'))
|
190
|
+
}
|
191
|
+
|
192
|
+
expected_rum_script = "<script type=\"text/javascript\">(window.StackifySettings || (window.StackifySettings = #{rum_settings.to_json()}))<\/script><script src=\"#{rum_script_url}\" data-key=\"#{rum_key}\" async></script>"
|
193
|
+
|
194
|
+
allow(rum).to receive(:get_reporting_url).and_return(reporting_url)
|
195
|
+
allow(rum).to receive(:get_transaction_id).and_return(transaction_id)
|
196
|
+
allow(Rum).to receive(:apm_loaded).and_return(false)
|
197
|
+
|
198
|
+
rum_script = rum.insert_rum_script
|
199
|
+
|
200
|
+
expect(rum.get_reporting_url).to eq reporting_url
|
201
|
+
expect(rum.get_transaction_id).to eq transaction_id
|
202
|
+
expect(rum_script.to_s).not_to be_empty
|
203
|
+
expect(rum_script).to eq expected_rum_script
|
204
|
+
expect(config.env).to eq :production
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'returns rum script with no transaction id' do
|
208
|
+
config = Stackify::Configuration.new
|
209
|
+
config.app_name = 'test'
|
210
|
+
config.env = 'test-env'
|
211
|
+
config.rum_script_url = 'test.js'
|
212
|
+
config.rum_key = 'asd'
|
213
|
+
|
214
|
+
rum = Stackify::Rum.new(config)
|
215
|
+
|
216
|
+
reporting_url = "test reporting url"
|
217
|
+
transaction_id = ""
|
218
|
+
|
219
|
+
allow(rum).to receive(:get_reporting_url).and_return(reporting_url)
|
220
|
+
allow(rum).to receive(:get_transaction_id).and_return(transaction_id)
|
221
|
+
allow(Rum).to receive(:apm_loaded).and_return(false)
|
222
|
+
|
223
|
+
rum_script = rum.insert_rum_script
|
224
|
+
|
225
|
+
expect(rum.get_reporting_url).to eq reporting_url
|
226
|
+
expect(rum.get_transaction_id).to eq ""
|
227
|
+
expect(rum_script.to_s).to be_empty
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'returns rum script with no reporting url' do
|
231
|
+
config = Stackify::Configuration.new
|
232
|
+
config.app_name = 'test'
|
233
|
+
config.env = 'test-env'
|
234
|
+
config.rum_script_url = 'test.js'
|
235
|
+
config.rum_key = 'asd'
|
236
|
+
|
237
|
+
rum = Stackify::Rum.new(config)
|
238
|
+
|
239
|
+
reporting_url = ""
|
240
|
+
transaction_id = "test-123"
|
241
|
+
|
242
|
+
allow(rum).to receive(:get_reporting_url).and_return(reporting_url)
|
243
|
+
allow(rum).to receive(:get_transaction_id).and_return(transaction_id)
|
244
|
+
allow(Rum).to receive(:apm_loaded).and_return(false)
|
245
|
+
|
246
|
+
rum_script = rum.insert_rum_script
|
247
|
+
|
248
|
+
expect(rum.get_reporting_url).to eq ""
|
249
|
+
expect(rum.get_transaction_id).to eq transaction_id
|
250
|
+
expect(rum_script.to_s).to be_empty
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
RSpec.describe 'Rum - APM loaded - Normal' do
|
255
|
+
it 'returns rum script with complete information from ENV' do
|
256
|
+
ENV['RETRACE_RUM_KEY'] = 'test-key'
|
257
|
+
ENV['RETRACE_RUM_SCRIPT_URL'] = 'https://test.com/test.js'
|
258
|
+
ENV['TZ'] = 'Europe/Paris' # For error
|
259
|
+
|
260
|
+
config = Stackify::Configuration.new
|
261
|
+
rum = Stackify::Rum.new(config)
|
262
|
+
reporting_url = "test reporting url"
|
263
|
+
transaction_id = "123-id"
|
264
|
+
rum_script_url = 'https://test.com/test.js'
|
265
|
+
rum_script = ""
|
266
|
+
|
267
|
+
StackifyRubyAPM.start
|
268
|
+
transaction = StackifyRubyAPM.transaction 'RUM Script Injection test' do
|
269
|
+
rum_script = rum.insert_rum_script
|
270
|
+
end.submit 200
|
271
|
+
StackifyRubyAPM.stop
|
272
|
+
|
273
|
+
rum_settings = {
|
274
|
+
"ID" => transaction.id(),
|
275
|
+
"Env" => Base64.strict_encode64('test'.encode('utf-8')),
|
276
|
+
"Name" => Base64.strict_encode64('Ruby Application'.strip.encode('utf-8')), # TODO: Add helper function
|
277
|
+
"Trans" => Base64.strict_encode64('RUM Script Injection test'.encode('utf-8'))
|
278
|
+
}
|
279
|
+
|
280
|
+
expected_rum_script = "<script type=\"text/javascript\">(window.StackifySettings || (window.StackifySettings = #{rum_settings.to_json()}))<\/script><script src=\"#{rum_script_url}\" data-key=\"#{config.rum_key}\" async></script>"
|
281
|
+
|
282
|
+
ENV.delete('TZ')
|
283
|
+
ENV.delete('RETRACE_RUM_KEY')
|
284
|
+
ENV.delete('RETRACE_RUM_SCRIPT_URL')
|
285
|
+
|
286
|
+
expect(rum_script.to_s).not_to be_empty
|
287
|
+
expect(rum_script).to eq expected_rum_script
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
ENV['RAILS_ENV'] = ENV['RACK_ENV'] = 'test'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
# auto-require default gems + gems under test
|
5
|
+
Bundler.require :default, 'test'
|
6
|
+
|
7
|
+
require 'logger'
|
8
|
+
require 'stackify_ruby_apm'
|
9
|
+
|
1
10
|
RSpec.configure do |config|
|
2
11
|
|
3
12
|
config.filter_run :focus
|
data/stackify-api-ruby.gemspec
CHANGED
@@ -21,7 +21,12 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
23
23
|
spec.add_development_dependency 'rake', '~> 0'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
25
|
+
|
26
|
+
if RUBY_PLATFORM == 'i386-mingw32'
|
27
|
+
spec.add_development_dependency 'tzinfo-data'
|
28
|
+
end
|
29
|
+
|
24
30
|
spec.add_runtime_dependency 'faraday', '~> 0.8'
|
25
|
-
spec.add_runtime_dependency 'google-protobuf', '~> 3.0'
|
26
31
|
spec.add_runtime_dependency 'net_http_unix', '~> 0.2'
|
27
32
|
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.
|
4
|
+
version: 1.3.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stackify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -39,33 +39,33 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0
|
48
|
-
type: :
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0
|
54
|
+
version: '3.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: faraday
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0.8'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0.8'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: net_http_unix
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,7 +95,6 @@ files:
|
|
95
95
|
- README.md
|
96
96
|
- Rakefile
|
97
97
|
- lib/core_ext/core_ext.rb
|
98
|
-
- lib/core_ext/fixnum.rb
|
99
98
|
- lib/core_ext/object.rb
|
100
99
|
- lib/generators/stackify/stackify_generator.rb
|
101
100
|
- lib/generators/stackify/templates/stackify.rb
|
@@ -123,6 +122,7 @@ files:
|
|
123
122
|
- lib/stackify/metrics/monitor.rb
|
124
123
|
- lib/stackify/msgs_queue.rb
|
125
124
|
- lib/stackify/rack/errors_catcher.rb
|
125
|
+
- lib/stackify/rum.rb
|
126
126
|
- lib/stackify/schedule_delay.rb
|
127
127
|
- lib/stackify/schedule_task.rb
|
128
128
|
- lib/stackify/scheduler.rb
|
@@ -139,6 +139,7 @@ files:
|
|
139
139
|
- lib/stackify/workers/logs_sender_worker.rb
|
140
140
|
- lib/stackify/workers/msgs_queue_worker.rb
|
141
141
|
- lib/stackify/workers/worker.rb
|
142
|
+
- spec/rum_spec.rb
|
142
143
|
- spec/spec_helper.rb
|
143
144
|
- stackify-api-ruby.gemspec
|
144
145
|
homepage: http://www.stackify.com/
|
@@ -156,13 +157,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
157
|
version: '1.9'
|
157
158
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
159
|
requirements:
|
159
|
-
- - "
|
160
|
+
- - ">"
|
160
161
|
- !ruby/object:Gem::Version
|
161
|
-
version:
|
162
|
+
version: 1.3.1
|
162
163
|
requirements: []
|
163
164
|
rubygems_version: 3.0.1
|
164
165
|
signing_key:
|
165
166
|
specification_version: 4
|
166
167
|
summary: Stackify API for Ruby
|
167
168
|
test_files:
|
169
|
+
- spec/rum_spec.rb
|
168
170
|
- spec/spec_helper.rb
|
data/lib/core_ext/fixnum.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
class Fixnum
|
2
|
-
SECONDS_IN_MINUTE = 60
|
3
|
-
SECONDS_IN_HOUR = 60 * SECONDS_IN_MINUTE
|
4
|
-
SECONDS_IN_DAY = 24 * SECONDS_IN_HOUR
|
5
|
-
|
6
|
-
def days
|
7
|
-
self * SECONDS_IN_DAY
|
8
|
-
end
|
9
|
-
|
10
|
-
def minutes
|
11
|
-
self * SECONDS_IN_MINUTE
|
12
|
-
end
|
13
|
-
|
14
|
-
def ago
|
15
|
-
Time.now - self
|
16
|
-
end
|
17
|
-
end
|