appsignal 2.8.0.alpha.1-java → 2.8.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,91 @@
1
+ module Appsignal
2
+ class CLI
3
+ class Diagnose
4
+ class Paths
5
+ BYTES_TO_READ_FOR_FILES = 2 * 1024 * 1024 # 2 Mebibytes
6
+
7
+ def report
8
+ {}.tap do |hash|
9
+ paths.each do |filename, config|
10
+ hash[filename] = path_stat(config[:path])
11
+ end
12
+ end
13
+ end
14
+
15
+ def paths
16
+ @paths ||=
17
+ begin
18
+ config = Appsignal.config
19
+ log_file_path = config.log_file_path
20
+ install_log_path = File.join("ext", "install.log")
21
+ makefile_log_path = File.join("ext", "mkmf.log")
22
+ {
23
+ :package_install_path => {
24
+ :label => "AppSignal gem path",
25
+ :path => gem_path
26
+ },
27
+ :working_dir => {
28
+ :label => "Current working directory",
29
+ :path => Dir.pwd
30
+ },
31
+ :root_path => {
32
+ :label => "Root path",
33
+ :path => config.root_path
34
+ },
35
+ :log_dir_path => {
36
+ :label => "Log directory",
37
+ :path => log_file_path ? File.dirname(log_file_path) : ""
38
+ },
39
+ install_log_path => {
40
+ :label => "Extension install log",
41
+ :path => File.join(gem_path, install_log_path)
42
+ },
43
+ makefile_log_path => {
44
+ :label => "Makefile install log",
45
+ :path => File.join(gem_path, makefile_log_path)
46
+ },
47
+ "appsignal.log" => {
48
+ :label => "AppSignal log",
49
+ :path => log_file_path
50
+ }
51
+ }
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def path_stat(path)
58
+ {
59
+ :path => path,
60
+ :exists => File.exist?(path)
61
+ }.tap do |info|
62
+ next unless info[:exists]
63
+ stat = File.stat(path)
64
+ info[:type] = stat.directory? ? "directory" : "file"
65
+ info[:mode] = format("%o", stat.mode)
66
+ info[:writable] = stat.writable?
67
+ path_uid = stat.uid
68
+ path_gid = stat.gid
69
+ info[:ownership] = {
70
+ :uid => path_uid,
71
+ :user => Utils.username_for_uid(path_uid),
72
+ :gid => path_gid,
73
+ :group => Utils.group_for_gid(path_gid)
74
+ }
75
+ if info[:type] == "file"
76
+ info[:content] = Utils.read_file_content(
77
+ path,
78
+ BYTES_TO_READ_FOR_FILES
79
+ ).split("\n")
80
+ end
81
+ end
82
+ end
83
+
84
+ def gem_path
85
+ @gem_path ||= \
86
+ Bundler::CLI::Common.select_spec("appsignal").full_gem_path.strip
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,36 @@
1
+ module Appsignal
2
+ class CLI
3
+ class Diagnose
4
+ class Utils
5
+ def self.username_for_uid(uid)
6
+ passwd_struct = Etc.getpwuid(uid)
7
+ return unless passwd_struct
8
+ passwd_struct.name
9
+ end
10
+
11
+ def self.group_for_gid(gid)
12
+ passwd_struct = Etc.getgrgid(gid)
13
+ return unless passwd_struct
14
+ passwd_struct.name
15
+ end
16
+
17
+ def self.read_file_content(path, bytes_to_read)
18
+ file_size = File.size(path)
19
+ if bytes_to_read > file_size
20
+ # When the file is smaller than the bytes_to_read
21
+ # Read the whole file
22
+ offset = 0
23
+ length = file_size
24
+ else
25
+ # When the file is smaller than the bytes_to_read
26
+ # Read the last X bytes_to_read
27
+ length = bytes_to_read
28
+ offset = file_size - bytes_to_read
29
+ end
30
+
31
+ IO.binread(path, length, offset)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -73,10 +73,10 @@ module Appsignal
73
73
  end
74
74
 
75
75
  def install_for_rails(config)
76
- require File.expand_path(File.join(Dir.pwd, "config/application.rb"))
77
-
78
76
  puts "Installing for Ruby on Rails"
79
77
 
78
+ require File.expand_path(File.join(Dir.pwd, "config/application.rb"))
79
+
80
80
  config[:name] = Rails.application.class.parent_name
81
81
 
82
82
  name_overwritten = yes_or_no(" Your app's name is: '#{config[:name]}' \n Do you want to change how this is displayed in AppSignal? (y/n): ")
@@ -8,6 +8,8 @@ require "tmpdir"
8
8
 
9
9
  module Appsignal
10
10
  class Config
11
+ include Appsignal::Utils::DeprecationMessage
12
+
11
13
  DEFAULT_CONFIG = {
12
14
  :debug => false,
13
15
  :log => "file",
@@ -82,27 +84,69 @@ module Appsignal
82
84
  :ignore_exceptions => :ignore_errors
83
85
  }.freeze
84
86
 
85
- attr_reader :root_path, :env, :initial_config, :config_hash
87
+ # @attribute [r] system_config
88
+ # Config detected on the system level.
89
+ # Used in diagnose report.
90
+ # @api private
91
+ # @return [Hash]
92
+ # @!attribute [r] initial_config
93
+ # Config detected on the system level.
94
+ # Used in diagnose report.
95
+ # @api private
96
+ # @return [Hash]
97
+ # @!attribute [r] file_config
98
+ # Config loaded from `config/appsignal.yml` config file.
99
+ # Used in diagnose report.
100
+ # @api private
101
+ # @return [Hash]
102
+ # @!attribute [r] env_config
103
+ # Config loaded from the system environment.
104
+ # Used in diagnose report.
105
+ # @api private
106
+ # @return [Hash]
107
+ # @!attribute [r] config_hash
108
+ # Config used by the AppSignal gem.
109
+ # Combined Hash of the {system_config}, {initial_config}, {file_config},
110
+ # {env_config} attributes.
111
+ # @see #[]
112
+ # @see #[]=
113
+ # @api private
114
+ # @return [Hash]
115
+
116
+ attr_reader :root_path, :env, :config_hash, :system_config,
117
+ :initial_config, :file_config, :env_config
86
118
  attr_accessor :logger
87
119
 
88
120
  def initialize(root_path, env, initial_config = {}, logger = Appsignal.logger)
89
121
  @root_path = root_path
90
- @env = ENV.fetch("APPSIGNAL_APP_ENV".freeze, env.to_s)
91
- @initial_config = initial_config
92
122
  @logger = logger
93
123
  @valid = false
94
124
  @config_hash = Hash[DEFAULT_CONFIG]
125
+ env_loaded_from_initial = env.to_s
126
+ @env =
127
+ if ENV.key?("APPSIGNAL_APP_ENV".freeze)
128
+ env_loaded_from_env = ENV["APPSIGNAL_APP_ENV".freeze]
129
+ else
130
+ env_loaded_from_initial
131
+ end
95
132
 
96
133
  # Set config based on the system
97
- detect_from_system
134
+ @system_config = detect_from_system
135
+ merge(system_config)
98
136
  # Initial config
99
- merge(@config_hash, initial_config)
137
+ @initial_config = initial_config
138
+ merge(initial_config)
100
139
  # Load the config file if it exists
101
- load_from_disk
140
+ @file_config = load_from_disk || {}
141
+ merge(file_config)
102
142
  # Load config from environment variables
103
- load_from_environment
143
+ @env_config = load_from_environment
144
+ merge(env_config)
104
145
  # Validate that we have a correct config
105
146
  validate
147
+ # Track origin of env
148
+ @initial_config[:env] = env_loaded_from_initial if env_loaded_from_initial
149
+ @env_config[:env] = env_loaded_from_env if env_loaded_from_env
106
150
  end
107
151
 
108
152
  # @api private
@@ -166,7 +210,6 @@ module Appsignal
166
210
  ENV["_APPSIGNAL_IGNORE_ACTIONS"] = config_hash[:ignore_actions].join(",")
167
211
  ENV["_APPSIGNAL_IGNORE_ERRORS"] = config_hash[:ignore_errors].join(",")
168
212
  ENV["_APPSIGNAL_IGNORE_NAMESPACES"] = config_hash[:ignore_namespaces].join(",")
169
- ENV["_APPSIGNAL_SEND_PARAMS"] = config_hash[:send_params].to_s
170
213
  ENV["_APPSIGNAL_RUNNING_IN_CONTAINER"] = config_hash[:running_in_container].to_s
171
214
  ENV["_APPSIGNAL_WORKING_DIR_PATH"] = config_hash[:working_dir_path] if config_hash[:working_dir_path]
172
215
  ENV["_APPSIGNAL_WORKING_DIRECTORY_PATH"] = config_hash[:working_directory_path] if config_hash[:working_directory_path]
@@ -208,10 +251,12 @@ module Appsignal
208
251
  end
209
252
 
210
253
  def detect_from_system
211
- config_hash[:log] = "stdout" if Appsignal::System.heroku?
254
+ {}.tap do |hash|
255
+ hash[:log] = "stdout" if Appsignal::System.heroku?
212
256
 
213
- # Make active by default if APPSIGNAL_PUSH_API_KEY is present
214
- config_hash[:active] = true if ENV["APPSIGNAL_PUSH_API_KEY"]
257
+ # Make active by default if APPSIGNAL_PUSH_API_KEY is present
258
+ hash[:active] = true if ENV["APPSIGNAL_PUSH_API_KEY"]
259
+ end
215
260
  end
216
261
 
217
262
  def load_from_disk
@@ -225,11 +270,10 @@ module Appsignal
225
270
  hash[key.to_sym] = value # convert keys to symbols
226
271
  end
227
272
 
228
- config_for_this_env = maintain_backwards_compatibility(config_for_this_env)
229
-
230
- merge(@config_hash, config_for_this_env)
273
+ maintain_backwards_compatibility(config_for_this_env)
231
274
  else
232
275
  @logger.error "Not loading from config file: config for '#{env}' not found"
276
+ nil
233
277
  end
234
278
  end
235
279
 
@@ -242,17 +286,21 @@ module Appsignal
242
286
  DEPRECATED_CONFIG_KEY_MAPPING.each do |old_key, new_key|
243
287
  old_config_value = config.delete(old_key)
244
288
  next unless old_config_value
245
- logger.warn "Old configuration key found. Please update the "\
246
- "'#{old_key}' to '#{new_key}'."
289
+ deprecation_message \
290
+ "Old configuration key found. Please update the "\
291
+ "'#{old_key}' to '#{new_key}'.",
292
+ logger
247
293
 
248
294
  next if config[new_key] # Skip if new key is already in use
249
295
  config[new_key] = old_config_value
250
296
  end
251
297
 
252
298
  if config.include?(:working_dir_path)
253
- logger.warn "'working_dir_path' is deprecated, please use " \
254
- "'working_directory_path' instead and specify the " \
255
- "full path to the working directory"
299
+ deprecation_message \
300
+ "'working_dir_path' is deprecated, please use " \
301
+ "'working_directory_path' instead and specify the " \
302
+ "full path to the working directory",
303
+ logger
256
304
  end
257
305
  end
258
306
  end
@@ -292,15 +340,15 @@ module Appsignal
292
340
  config[ENV_TO_KEY_MAPPING[var]] = env_var.split(",")
293
341
  end
294
342
 
295
- merge(@config_hash, config)
343
+ config
296
344
  end
297
345
 
298
- def merge(original_config, new_config)
346
+ def merge(new_config)
299
347
  new_config.each do |key, value|
300
- unless original_config[key].nil?
348
+ unless config_hash[key].nil?
301
349
  @logger.debug("Config key '#{key}' is being overwritten")
302
350
  end
303
- original_config[key] = value
351
+ config_hash[key] = value
304
352
  end
305
353
  end
306
354
  end
@@ -14,6 +14,8 @@ module Appsignal
14
14
  # @api private
15
15
  class EventFormatter
16
16
  class << self
17
+ include Appsignal::Utils::DeprecationMessage
18
+
17
19
  def formatters
18
20
  @@formatters ||= {}
19
21
  end
@@ -33,7 +35,7 @@ module Appsignal
33
35
  end
34
36
 
35
37
  if registered?(name, formatter)
36
- Appsignal.logger.warn(
38
+ logger.warn(
37
39
  "Formatter for '#{name}' already registered, not registering "\
38
40
  "'#{formatter.name}'"
39
41
  )
@@ -82,19 +84,23 @@ module Appsignal
82
84
  rescue => ex
83
85
  formatter_classes.delete(name)
84
86
  formatters.delete(name)
85
- Appsignal.logger.warn("'#{ex.message}' when initializing #{name} event formatter")
87
+ logger.warn("'#{ex.message}' when initializing #{name} event formatter")
86
88
  end
87
89
 
88
90
  def register_deprecated_formatter(name)
89
- Appsignal.logger.warn(
91
+ deprecation_message \
90
92
  "Formatter for '#{name}' is using a deprecated registration " \
91
93
  "method. This event formatter will not be loaded. " \
92
94
  "Please update the formatter according to the documentation at: " \
93
- "https://docs.appsignal.com/ruby/instrumentation/event-formatters.html"
94
- )
95
+ "https://docs.appsignal.com/ruby/instrumentation/event-formatters.html",
96
+ logger
95
97
 
96
98
  deprecated_formatter_classes[name] = self
97
99
  end
100
+
101
+ def logger
102
+ Appsignal.logger
103
+ end
98
104
  end
99
105
 
100
106
  # @api public
@@ -47,4 +47,15 @@ module Appsignal
47
47
  self.class.lock
48
48
  end
49
49
  end
50
+
51
+ # {Appsignal::NilGarbageCollectionProfiler} is a dummy profiler
52
+ # that always returns 0 as the total time.
53
+ # Used when we don't want any profile information
54
+ #
55
+ # @api private
56
+ class NilGarbageCollectionProfiler
57
+ def total_time
58
+ 0
59
+ end
60
+ end
50
61
  end
@@ -7,7 +7,9 @@ module Appsignal
7
7
  #
8
8
  # @api private
9
9
  module System
10
+ LINUX_TARGET = "linux".freeze
10
11
  MUSL_TARGET = "linux-musl".freeze
12
+ FREEBSD_TARGET = "freebsd".freeze
11
13
  GEM_EXT_PATH = File.expand_path("../../../ext", __FILE__).freeze
12
14
 
13
15
  def self.heroku?
@@ -45,12 +47,12 @@ module Appsignal
45
47
  host_os = RbConfig::CONFIG["host_os"].downcase
46
48
  local_os =
47
49
  case host_os
48
- when /linux/
49
- "linux"
50
+ when /#{LINUX_TARGET}/
51
+ LINUX_TARGET
50
52
  when /darwin/
51
53
  "darwin"
52
- when /freebsd/
53
- "freebsd"
54
+ when /#{FREEBSD_TARGET}/
55
+ FREEBSD_TARGET
54
56
  else
55
57
  host_os
56
58
  end
@@ -53,7 +53,8 @@ module Appsignal
53
53
  end
54
54
 
55
55
  def garbage_collection_profiler
56
- @garbage_collection_profiler ||= Appsignal::GarbageCollectionProfiler.new
56
+ @garbage_collection_profiler ||=
57
+ Appsignal.config[:enable_gc_instrumentation] ? Appsignal::GarbageCollectionProfiler.new : NilGarbageCollectionProfiler.new
57
58
  end
58
59
  end
59
60
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "appsignal/utils/deprecation_message"
3
4
  require "appsignal/utils/data"
4
5
  require "appsignal/utils/hash_sanitizer"
5
6
  require "appsignal/utils/json"
@@ -0,0 +1,10 @@
1
+ module Appsignal
2
+ module Utils
3
+ module DeprecationMessage
4
+ def deprecation_message(message, logger)
5
+ $stdout.puts "appsignal WARNING: #{message}"
6
+ logger.warn message
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "2.8.0.alpha.1".freeze
4
+ VERSION = "2.8.0".freeze
5
5
  end
@@ -0,0 +1,37 @@
1
+ require "appsignal/cli/diagnose/utils"
2
+
3
+ describe Appsignal::CLI::Diagnose::Utils do
4
+ describe ".read_file_content" do
5
+ let(:path) { File.join(spec_system_tmp_dir, "test_file.txt") }
6
+ let(:bytes_to_read) { 100 }
7
+ subject { described_class.read_file_content(path, bytes_to_read) }
8
+ before do
9
+ File.open path, "w+" do |f|
10
+ f.write file_contents
11
+ end
12
+ end
13
+
14
+ context "when file is bigger than read size" do
15
+ let(:file_contents) do
16
+ "".tap do |s|
17
+ 100.times do |i|
18
+ s << "line #{i}\n"
19
+ end
20
+ end
21
+ end
22
+
23
+ it "returns the last X bytes" do
24
+ is_expected
25
+ .to eq(file_contents[(file_contents.length - bytes_to_read)..file_contents.length])
26
+ end
27
+ end
28
+
29
+ context "when file is smaller than read size" do
30
+ let(:file_contents) { "line 1\n" }
31
+
32
+ it "returns the whole file content" do
33
+ is_expected.to eq(file_contents)
34
+ end
35
+ end
36
+ end
37
+ end