appsignal 4.1.2 → 4.2.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: a620112e4e2973bbe98b2cd233960559d037edabeaf84c3230fdf96c9784d00d
4
- data.tar.gz: c0c933abb03dcbf90b97f60a101821a27922d3f9882eb7e30e1c5aadccd19018
3
+ metadata.gz: 83c3f6a3607f3e28d1b95b790b1eec081673e596db8ed02a868bc31eb54fe884
4
+ data.tar.gz: a2f57f3c3604fb05953949114cf2e3a315c0ab61af40c0d50ee59a2a0c23a87a
5
5
  SHA512:
6
- metadata.gz: a27e63dfb9ef37d49844d283ff0526f418cc042d03a2e2155c46e8e0589db36b05834d121a6d88d8b9066642b657cefeb19a549130dec2025541a7250fed26ff
7
- data.tar.gz: f439966b51ea704309eef8422ebfbb098d98c850cae7084f0532b50f45c558ecbf5f87888b23f7337f916e25f7ea35b3868e935ee2eaab3c84a3f12766305645
6
+ metadata.gz: 108fd4431a1fd08f619ff084b8304dddd25bfc1cadf218265bdc12f7dc3e7609a551daa2b6e1a9c433dcdca5a51bccf5c916be12700bdd880b03aca422d03ca0
7
+ data.tar.gz: 1243f5f9894c7c7750bbd991a4e9dc7b6b8c5d80f4fd68e77798cccb97b41dc7efd7039e4e3176178f9fda0804c67643f2770098d34ff8c4105f8005320a6799
data/CHANGELOG.md CHANGED
@@ -1,5 +1,190 @@
1
1
  # AppSignal for Ruby gem Changelog
2
2
 
3
+ ## 4.2.0
4
+
5
+ _Published on 2024-11-13._
6
+
7
+ ### Added
8
+
9
+ - Add `config/appsignal.rb` config file support. When a `config/appsignal.rb` file is present in the app, the Ruby gem will automatically load it when `Appsignal.start` is called.
10
+
11
+ The `config/appsignal.rb` config file is a replacement for the `config/appsignal.yml` config file. When both files are present, only the `config/appsignal.rb` config file is loaded when the configuration file is automatically loaded by AppSignal when the configuration file is automatically loaded by AppSignal.
12
+
13
+ Example `config/appsignal.rb` config file:
14
+
15
+ ```ruby
16
+ # config/appsignal.rb
17
+ Appsignal.configure do |config|
18
+ config.name = "My app name"
19
+ end
20
+ ```
21
+
22
+ To configure different option values for environments in the `config/appsignal.rb` config file, use if-statements:
23
+
24
+ ```ruby
25
+ # config/appsignal.rb
26
+ Appsignal.configure do |config|
27
+ config.name = "My app name"
28
+ if config.env == "production"
29
+ config.ignore_actions << "My production action"
30
+ end
31
+ if config.env == "staging"
32
+ config.ignore_actions << "My staging action"
33
+ end
34
+ end
35
+ ```
36
+
37
+ (minor [f81248bc](https://github.com/appsignal/appsignal-ruby/commit/f81248bc9c557197a0dd123c6d5958f21c11af9d), [48d16c7a](https://github.com/appsignal/appsignal-ruby/commit/48d16c7ab4dbc35ac3d56ecf042ca165d609bb64))
38
+ - Add the `config/appsignal.rb` Ruby config file method to installer, `appsignal install`. (patch [0d2e2bde](https://github.com/appsignal/appsignal-ruby/commit/0d2e2bde5da510f0d339673cdcdb9f79030acf59))
39
+ - Add `Appsignal.set_empty_params!` helper method. This helper method can be used to unset parameters on a transaction and to prevent the Appsignal instrumentation from adding parameters to a transaction.
40
+
41
+ Example usage:
42
+
43
+ ```ruby
44
+ class PaymentsController < ApplicationController
45
+ def create
46
+ Appsignal.set_empty_params!
47
+
48
+ # Do things with sensitive parameters
49
+ end
50
+ end
51
+ ```
52
+
53
+ When `Appsignal.add_params` is called afterward, the "empty parameters" state is cleared and any AppSignal instrumentation (if called afterward) will also add parameters again.
54
+
55
+ ```ruby
56
+ # Example: Unset parameters when set
57
+ Appsignal.add_params("abc" => "def")
58
+ # Parameters: { "abc" => "def" }
59
+ Appsignal.set_empty_params!
60
+ # Parameters: {}
61
+
62
+ # Example: When AppSignal instrumentation sets parameters:
63
+ Appsignal.set_empty_params!
64
+ # Parameters: {}
65
+ # Pseudo example code:
66
+ Appsignal::Instrumentation::SomeLibrary.new.add_params("xyz" => "...")
67
+ # Parameters: {}
68
+
69
+ # Example: Set parameters after them being unset previously
70
+ Appsignal.set_empty_params!
71
+ # Parameters: {}
72
+ Appsignal.add_params("abc" => "def")
73
+ # Parameters: { "abc" => "def" }
74
+ ```
75
+
76
+ (patch [20a8050e](https://github.com/appsignal/appsignal-ruby/commit/20a8050e63605f08e9377dda84b3a422810dd49a), [23627cd7](https://github.com/appsignal/appsignal-ruby/commit/23627cd7e7c2b2939c43701228e77aa14eae5c68))
77
+ - Add `Appsignal.configure` context `env?` helper method. Check if the loaded environment matches the given environment using the `.env?(:env_name)` helper.
78
+
79
+ Example:
80
+
81
+ ```ruby
82
+ Appsignal.configure do |config|
83
+ # Symbols work as the argument
84
+ if config.env?(:production)
85
+ config.ignore_actions << "My production action"
86
+ end
87
+
88
+ # Strings also work as the argument
89
+ if config.env?("staging")
90
+ config.ignore_actions << "My staging action"
91
+ end
92
+ end
93
+ ```
94
+
95
+ (patch [8b234cae](https://github.com/appsignal/appsignal-ruby/commit/8b234caee4c29f9550c4dc77d02ebd21f8dbfa30))
96
+ - Allow for default attributes to be given when initialising a `Logger` instance:
97
+
98
+ ```ruby
99
+ order_logger = Appsignal::Logger.new("app", attributes: { order_id: 123 })
100
+ ```
101
+
102
+ All log lines reported by this logger will contain the given attribute. Attributes given when reporting the log line will be merged with the default attributes for the logger, with those in the log line taking priority.
103
+
104
+ (patch [27e05af6](https://github.com/appsignal/appsignal-ruby/commit/27e05af6cb1e1ebca1fd6e8038da290f42db2bdb), [8be7c791](https://github.com/appsignal/appsignal-ruby/commit/8be7c7912eea4d3df74f1ca8808b7d6e8802f550))
105
+
106
+ ### Changed
107
+
108
+ - Read the Hanami Action name without metaprogramming in Hanami 2.2 and newer. This makes our instrumentation more stable whenever something changes in future Hanami releases. (patch [c6848504](https://github.com/appsignal/appsignal-ruby/commit/c68485043feee13a49400f57c9a77d48f670f0f2))
109
+ - Ignore these Hanami errors by default:
110
+
111
+ - Hanami::Router::NotAllowedError (for example: sending a GET request to POST endpoint)
112
+ - Hanami::Router::NotFoundError
113
+
114
+ They are usually errors you don't want to be notified about, so we ignore them by default now.
115
+
116
+ Customize the `ignore_errors` config option to continue receiving these errors.
117
+
118
+ (patch [f1500987](https://github.com/appsignal/appsignal-ruby/commit/f1500987b7b73ab2873202ea7301f2cfb19acdc7))
119
+
120
+ ### Fixed
121
+
122
+ - Fix request parameter reporting for Hanami 2.2. (patch [ca22ed54](https://github.com/appsignal/appsignal-ruby/commit/ca22ed54de513773c5ee387f28ad98ee8f301627))
123
+
124
+ ## 4.1.3
125
+
126
+ _Published on 2024-11-07._
127
+
128
+ ### Added
129
+
130
+ - Add `activate_if_environment` helper for `Appsignal.configure`. Avoid having to add conditionals to your configuration file and use the `activate_if_environment` helper to specify for which environments AppSignal should become active. AppSignal will automatically detect the environment and activate itself it the environment matches one of the listed environments.
131
+
132
+ ```ruby
133
+ # Before
134
+ Appsignal.configure do |config|
135
+ config.active = Rails.env.production? || Rails.env.staging?
136
+ end
137
+
138
+ # After
139
+ Appsignal.configure do |config|
140
+ # Activate for one environment
141
+ config.activate_if_environment(:production)
142
+
143
+ # Activate for multiple environments
144
+ config.activate_if_environment(:production, :staging)
145
+ end
146
+ ```
147
+
148
+ (patch [ff31be88](https://github.com/appsignal/appsignal-ruby/commit/ff31be88cf49a18951f48663d96af3cde4184e32))
149
+ - Add a hostname AppSignal tag automatically, based on the OpenTelemetry `host.name` resource attribute. (Beta only) (patch [35449268](https://github.com/appsignal/appsignal-ruby/commit/35449268a5f6d7487d17018ddb8f5dd433d676e0))
150
+ - Add incident error count metric for enriched OpenTelemetry traces. (Beta only) (patch [35449268](https://github.com/appsignal/appsignal-ruby/commit/35449268a5f6d7487d17018ddb8f5dd433d676e0))
151
+ - Set the app revision config option for Scalingo deploys automatically. If the `CONTAINER_VERSION` system environment variable is present, it will use used to set the `revision` config option automatically. Overwrite it's value by configuring the `revision` config option for your application. (patch [35449268](https://github.com/appsignal/appsignal-ruby/commit/35449268a5f6d7487d17018ddb8f5dd433d676e0))
152
+
153
+ ### Changed
154
+
155
+ - Ignore the Rails healthcheck endpoint (Rails::HealthController#show) by default for Rails apps.
156
+
157
+ If the `ignore_actions` option is set in the `config/appsignal.yml` file, the default is overwritten.
158
+ If the `APPSIGNAL_IGNORE_ACTIONS` environment variable is set, the default is overwritten.
159
+ When using the `Appsignal.configure` helper, add more actions to the default like so:
160
+
161
+ ```ruby
162
+ # config/appsignal.rb
163
+ Appsignal.configure do |config|
164
+ # Add more actions to ignore
165
+ config.ignore_actions << "My action"
166
+ end
167
+ ```
168
+
169
+ To overwrite the default using the `Appsignal.configure` helper, do either of the following:
170
+
171
+ ```ruby
172
+ # config/appsignal.rb
173
+ Appsignal.configure do |config|
174
+ # Overwrite the default value, ignoring all actions ignored by default
175
+ config.ignore_actions = ["My action"]
176
+
177
+ # To only remove the healtcheck endpoint
178
+ config.ignore_actions.delete("Rails::HealthController#show")
179
+ end
180
+ ```
181
+
182
+ (patch [af71fb90](https://github.com/appsignal/appsignal-ruby/commit/af71fb904eebc4af05dc2fcf8bd390dd9baffd68))
183
+
184
+ ### Fixed
185
+
186
+ - Fix an issue where the extension fails to build on ARM64 Linux. (patch [79ac5bbe](https://github.com/appsignal/appsignal-ruby/commit/79ac5bbe7028151ae749cbd7a4e98f706d259ad8))
187
+
3
188
  ## 4.1.2
4
189
 
5
190
  _Published on 2024-10-04._
data/build_matrix.yml CHANGED
@@ -85,6 +85,7 @@ matrix:
85
85
  - "rails-7.0"
86
86
  - "rails-7.1"
87
87
  - "rails-7.2"
88
+ - "rails-8.0"
88
89
 
89
90
  ruby:
90
91
  - ruby: "3.3.4"
@@ -120,6 +121,12 @@ matrix:
120
121
  - "3.2.5"
121
122
  - "3.1.6"
122
123
  - "3.0.7"
124
+ - gem: "hanami-2.2"
125
+ only:
126
+ ruby:
127
+ - "3.3.4"
128
+ - "3.2.5"
129
+ - "3.1.6"
123
130
  - gem: "http5"
124
131
  - gem: "padrino"
125
132
  - gem: "psych-3"
@@ -179,6 +186,11 @@ matrix:
179
186
  - "3.2.5"
180
187
  - "3.1.6"
181
188
  - "jruby-9.4.7.0"
189
+ - gem: "rails-8.0"
190
+ only:
191
+ ruby:
192
+ - "3.3.4"
193
+ - "3.2.5"
182
194
  - gem: "sequel"
183
195
  - gem: "sinatra"
184
196
  - gem: "webmachine2"
data/ext/agent.rb CHANGED
@@ -6,7 +6,7 @@
6
6
  # Modifications to this file will be overwritten with the next agent release.
7
7
 
8
8
  APPSIGNAL_AGENT_CONFIG = {
9
- "version" => "0.35.26",
9
+ "version" => "0.35.28",
10
10
  "mirrors" => [
11
11
  "https://d135dj0rjqvssy.cloudfront.net",
12
12
  "https://appsignal-agent-releases.global.ssl.fastly.net"
@@ -14,131 +14,131 @@ APPSIGNAL_AGENT_CONFIG = {
14
14
  "triples" => {
15
15
  "x86_64-darwin" => {
16
16
  "static" => {
17
- "checksum" => "e0b0674dad04528f14048a0941fdacf9cbdb317627116c9b4dd7b786e572caa3",
17
+ "checksum" => "8759daae4f842a7dcf370e521de8de9390b3883e09abe8b4f868b6827c855bb3",
18
18
  "filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
19
19
  },
20
20
  "dynamic" => {
21
- "checksum" => "a30a6502787df7354da94e0c86eff92745b712d916cb2740a7fdb412add15ffc",
21
+ "checksum" => "bf65784cd4b082db18f241f02e21472f7356b59c5be1a1ef19788ffdac82e737",
22
22
  "filename" => "appsignal-x86_64-darwin-all-dynamic.tar.gz"
23
23
  }
24
24
  },
25
25
  "universal-darwin" => {
26
26
  "static" => {
27
- "checksum" => "e0b0674dad04528f14048a0941fdacf9cbdb317627116c9b4dd7b786e572caa3",
27
+ "checksum" => "8759daae4f842a7dcf370e521de8de9390b3883e09abe8b4f868b6827c855bb3",
28
28
  "filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
29
29
  },
30
30
  "dynamic" => {
31
- "checksum" => "a30a6502787df7354da94e0c86eff92745b712d916cb2740a7fdb412add15ffc",
31
+ "checksum" => "bf65784cd4b082db18f241f02e21472f7356b59c5be1a1ef19788ffdac82e737",
32
32
  "filename" => "appsignal-x86_64-darwin-all-dynamic.tar.gz"
33
33
  }
34
34
  },
35
35
  "aarch64-darwin" => {
36
36
  "static" => {
37
- "checksum" => "377d6eac5dc10de28275ec88a368f1c5da61438afa41f0767803d6c3a9399717",
37
+ "checksum" => "247551894b2195bb7e9cc6b52e8a42e10af0723b67f757d3eb84fe34791d0509",
38
38
  "filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
39
39
  },
40
40
  "dynamic" => {
41
- "checksum" => "45dfb897e2aaacbe7e638f88781d50059c6cb1fcce624e33bef409c75e70ac7f",
41
+ "checksum" => "21941505aed9051c31883e29e3b2de1816ef881ae68dc30cb0fd39104b5fcd4f",
42
42
  "filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
43
43
  }
44
44
  },
45
45
  "arm64-darwin" => {
46
46
  "static" => {
47
- "checksum" => "377d6eac5dc10de28275ec88a368f1c5da61438afa41f0767803d6c3a9399717",
47
+ "checksum" => "247551894b2195bb7e9cc6b52e8a42e10af0723b67f757d3eb84fe34791d0509",
48
48
  "filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
49
49
  },
50
50
  "dynamic" => {
51
- "checksum" => "45dfb897e2aaacbe7e638f88781d50059c6cb1fcce624e33bef409c75e70ac7f",
51
+ "checksum" => "21941505aed9051c31883e29e3b2de1816ef881ae68dc30cb0fd39104b5fcd4f",
52
52
  "filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
53
53
  }
54
54
  },
55
55
  "arm-darwin" => {
56
56
  "static" => {
57
- "checksum" => "377d6eac5dc10de28275ec88a368f1c5da61438afa41f0767803d6c3a9399717",
57
+ "checksum" => "247551894b2195bb7e9cc6b52e8a42e10af0723b67f757d3eb84fe34791d0509",
58
58
  "filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
59
59
  },
60
60
  "dynamic" => {
61
- "checksum" => "45dfb897e2aaacbe7e638f88781d50059c6cb1fcce624e33bef409c75e70ac7f",
61
+ "checksum" => "21941505aed9051c31883e29e3b2de1816ef881ae68dc30cb0fd39104b5fcd4f",
62
62
  "filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
63
63
  }
64
64
  },
65
65
  "aarch64-linux" => {
66
66
  "static" => {
67
- "checksum" => "67f927b89d9ef65f063c487bcd5bef832051a547d0b0f911589b4f90554c3185",
67
+ "checksum" => "02d62cfab5ab81faec40db6d80d47e53b2fca640026715697ab43f19539ace34",
68
68
  "filename" => "appsignal-aarch64-linux-all-static.tar.gz"
69
69
  },
70
70
  "dynamic" => {
71
- "checksum" => "291fbaddd0fb48d300268fe80c41b069d2669da2e592a27831b13e850983c247",
71
+ "checksum" => "8b580113f28781063be3538c8097c837ac85c3213c80d2597c00e32786921ef1",
72
72
  "filename" => "appsignal-aarch64-linux-all-dynamic.tar.gz"
73
73
  }
74
74
  },
75
75
  "i686-linux" => {
76
76
  "static" => {
77
- "checksum" => "aee4d5a74c0d5a39bf7047b2fb0c1ab0af4151bdf20b23c7095b024d8f34d6eb",
77
+ "checksum" => "d5771f360fbb24eb6d39459a910fcbb097904f8459a1735747dde3589c7d710d",
78
78
  "filename" => "appsignal-i686-linux-all-static.tar.gz"
79
79
  },
80
80
  "dynamic" => {
81
- "checksum" => "2bb793d036e7f605c0bb56b7c70a5107c4dd29a37966cdc33358287403b52c0a",
81
+ "checksum" => "03a066d55a5722802d053f8bdfdbe4bcb4ba9ee72b27d6a39aa62adad037f273",
82
82
  "filename" => "appsignal-i686-linux-all-dynamic.tar.gz"
83
83
  }
84
84
  },
85
85
  "x86-linux" => {
86
86
  "static" => {
87
- "checksum" => "aee4d5a74c0d5a39bf7047b2fb0c1ab0af4151bdf20b23c7095b024d8f34d6eb",
87
+ "checksum" => "d5771f360fbb24eb6d39459a910fcbb097904f8459a1735747dde3589c7d710d",
88
88
  "filename" => "appsignal-i686-linux-all-static.tar.gz"
89
89
  },
90
90
  "dynamic" => {
91
- "checksum" => "2bb793d036e7f605c0bb56b7c70a5107c4dd29a37966cdc33358287403b52c0a",
91
+ "checksum" => "03a066d55a5722802d053f8bdfdbe4bcb4ba9ee72b27d6a39aa62adad037f273",
92
92
  "filename" => "appsignal-i686-linux-all-dynamic.tar.gz"
93
93
  }
94
94
  },
95
95
  "x86_64-linux" => {
96
96
  "static" => {
97
- "checksum" => "595eef52453a179a6c5fde2a5d7206a85e07970a2dbceb631a19af20e05b46db",
97
+ "checksum" => "f3efd7973a0a4b5a0dca7ef23a896a866f011e70d90e2d22cd77c343ffbdf0c1",
98
98
  "filename" => "appsignal-x86_64-linux-all-static.tar.gz"
99
99
  },
100
100
  "dynamic" => {
101
- "checksum" => "018754bf36f98246d961caf2d115ce345bf6f74fa160c2cbfa733820cd787396",
101
+ "checksum" => "0900dd8f79838943532db19876018d95065b851eeb5f01c15dfb227bce7a01d8",
102
102
  "filename" => "appsignal-x86_64-linux-all-dynamic.tar.gz"
103
103
  }
104
104
  },
105
105
  "x86_64-linux-musl" => {
106
106
  "static" => {
107
- "checksum" => "5992db83dc784e4aaec4cc4d4ebbd62a9d68ae7197697c34f3d4d820233c3238",
107
+ "checksum" => "9e0cc593389e08527d2e62cc4389711a137511021fd59abd311da8ef5343aee6",
108
108
  "filename" => "appsignal-x86_64-linux-musl-all-static.tar.gz"
109
109
  },
110
110
  "dynamic" => {
111
- "checksum" => "4b93de4ba07614c313822ee5cbc1d2f3dea2c864fe91e3b0ec6c79927a9e58e5",
111
+ "checksum" => "b4420a303780e8733387338dca5a0f7dce03c4e0ec95526ec108bc66f39970ab",
112
112
  "filename" => "appsignal-x86_64-linux-musl-all-dynamic.tar.gz"
113
113
  }
114
114
  },
115
115
  "aarch64-linux-musl" => {
116
116
  "static" => {
117
- "checksum" => "f5d35cea12db1d473757d5fbed9c66e2018b6eaf35e0c96b2787f67e08ceae13",
117
+ "checksum" => "5112c3d0b22f27e6ed108d671ec2903f4cbe084c8d104a05bc946d88ccfed633",
118
118
  "filename" => "appsignal-aarch64-linux-musl-all-static.tar.gz"
119
119
  },
120
120
  "dynamic" => {
121
- "checksum" => "70309cff2e3f5330156c8ea530ccc537d4113eabe1d21590f8363c22803719fe",
121
+ "checksum" => "f15aaacdb197b114113c9a382ab371623e49ed0593af8a7d3c7d84aa10b77556",
122
122
  "filename" => "appsignal-aarch64-linux-musl-all-dynamic.tar.gz"
123
123
  }
124
124
  },
125
125
  "x86_64-freebsd" => {
126
126
  "static" => {
127
- "checksum" => "6a696cde1d84fbc56e152d560100bd941276e7b1ddda38de81bc3e985780366a",
127
+ "checksum" => "5d87cf82173f95440277b4565a58742c2843f0ddb17bf8f285023c294d1d30ad",
128
128
  "filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
129
129
  },
130
130
  "dynamic" => {
131
- "checksum" => "184e8fdb8bd69f0d0bd5fec1da66ae6ea87d2f447aac56e91d7a89e31c2c0cd0",
131
+ "checksum" => "9ba8d1c731212b23dccd76f22ad6979da160fe0d688f383acf8126c8922ecbdf",
132
132
  "filename" => "appsignal-x86_64-freebsd-all-dynamic.tar.gz"
133
133
  }
134
134
  },
135
135
  "amd64-freebsd" => {
136
136
  "static" => {
137
- "checksum" => "6a696cde1d84fbc56e152d560100bd941276e7b1ddda38de81bc3e985780366a",
137
+ "checksum" => "5d87cf82173f95440277b4565a58742c2843f0ddb17bf8f285023c294d1d30ad",
138
138
  "filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
139
139
  },
140
140
  "dynamic" => {
141
- "checksum" => "184e8fdb8bd69f0d0bd5fec1da66ae6ea87d2f447aac56e91d7a89e31c2c0cd0",
141
+ "checksum" => "9ba8d1c731212b23dccd76f22ad6979da160fe0d688f383acf8126c8922ecbdf",
142
142
  "filename" => "appsignal-x86_64-freebsd-all-dynamic.tar.gz"
143
143
  }
144
144
  }
@@ -188,15 +188,16 @@ module Appsignal
188
188
  end
189
189
 
190
190
  def configure_appsignal(options)
191
+ env_option = options.fetch(:environment, nil)
191
192
  # Try and load the Rails app, if any.
192
193
  # This will configure AppSignal through the config file or an
193
194
  # initializer.
194
- require_rails_app_if_present
195
+ require_rails_app_if_present(env_option)
195
196
 
196
- # If no config was found by loading the app, load with the defaults.
197
- Appsignal.configure(options.fetch(:environment, nil))
198
- Appsignal.config.write_to_environment
197
+ # No config loaded yet, try loading as normal
198
+ Appsignal._load_config!(env_option) unless Appsignal.config
199
199
  Appsignal._start_logger
200
+ Appsignal.config.write_to_environment
200
201
  Appsignal.internal_logger.info("Starting AppSignal diagnose")
201
202
  end
202
203
 
@@ -631,9 +632,12 @@ module Appsignal
631
632
  puts "\n"
632
633
  end
633
634
 
634
- def require_rails_app_if_present
635
+ def require_rails_app_if_present(env_option)
635
636
  return unless rails_present?
636
637
 
638
+ # Set the environment given as an option to the diagnose CLI so the
639
+ # Rails app uses it when loaded.
640
+ ENV["_APPSIGNAL_CONFIG_FILE_ENV"] = env_option
637
641
  # Mark app as Rails app
638
642
  data[:app][:rails] = true
639
643
  # Manually require the railtie, because it wasn't loaded when the CLI
@@ -649,6 +653,8 @@ module Appsignal
649
653
  puts error.backtrace
650
654
  data[:app][:load_error] =
651
655
  "#{error.class}: #{error.message}\n#{error.backtrace.join("\n")}"
656
+ ensure
657
+ ENV.delete("_APPSIGNAL_CONFIG_FILE_ENV")
652
658
  end
653
659
 
654
660
  def rails_present?
@@ -229,35 +229,49 @@ module Appsignal
229
229
  done_notice
230
230
  end
231
231
 
232
- def configure(config, environments, name_overwritten)
232
+ def configure(config, environments, name_overwritten) # rubocop:disable Metrics/AbcSize
233
233
  install_for_capistrano
234
234
 
235
235
  ENV["APPSIGNAL_APP_ENV"] = "development"
236
236
 
237
237
  puts "How do you want to configure AppSignal?"
238
- puts " (1) a config file"
239
- puts " (2) environment variables"
238
+ puts " (1) a Ruby config file"
239
+ puts " (2) a YAML config file (legacy)"
240
+ puts " (3) environment variables"
240
241
  puts
241
242
  puts " See our docs for information on the different configuration methods: "
242
243
  puts " https://docs.appsignal.com/ruby/configuration.html"
243
244
  puts
244
- loop do
245
- print " Choose (1/2): "
245
+ loop do # rubocop:disable Metrics/BlockLength
246
+ print " Choose (1-3): "
246
247
  case ask_for_input
247
248
  when "1"
248
249
  puts
249
- print "Writing config file"
250
+ print "Writing Ruby config file"
250
251
  periods
251
252
  puts
252
- puts colorize " Config file written to config/appsignal.yml", :green
253
- write_config_file(
253
+ write_ruby_config_file(
254
254
  :push_api_key => config[:push_api_key],
255
255
  :app_name => config[:name],
256
256
  :environments => environments
257
257
  )
258
+ puts colorize " Config file written to config/appsignal.rb", :green
258
259
  puts
259
260
  break
260
261
  when "2"
262
+ puts
263
+ print "Writing YAML config file"
264
+ periods
265
+ puts
266
+ write_yaml_config_file(
267
+ :push_api_key => config[:push_api_key],
268
+ :app_name => config[:name],
269
+ :environments => environments
270
+ )
271
+ puts colorize " Config file written to config/appsignal.yml", :green
272
+ puts
273
+ break
274
+ when "3"
261
275
  ENV["APPSIGNAL_ACTIVE"] = "true"
262
276
  ENV["APPSIGNAL_PUSH_API_KEY"] = config[:push_api_key]
263
277
  ENV["APPSIGNAL_APP_NAME"] = config[:name]
@@ -325,17 +339,37 @@ module Appsignal
325
339
  ).map { |o| File.basename(o, ".rb") }.sort - EXCLUDED_ENVIRONMENTS
326
340
  end
327
341
 
328
- def write_config_file(data)
329
- filename = File.join(
342
+ def write_ruby_config_file(data)
343
+ template = File.join(
344
+ File.dirname(__FILE__),
345
+ "../../../resources/appsignal.rb.erb"
346
+ )
347
+ write_config_file(
348
+ template,
349
+ File.join(Dir.pwd, "config/appsignal.rb"),
350
+ data
351
+ )
352
+ end
353
+
354
+ def write_yaml_config_file(data)
355
+ template = File.join(
330
356
  File.dirname(__FILE__),
331
357
  "../../../resources/appsignal.yml.erb"
332
358
  )
333
- file_contents = File.read(filename)
359
+ write_config_file(
360
+ template,
361
+ File.join(Dir.pwd, "config/appsignal.yml"),
362
+ data
363
+ )
364
+ end
365
+
366
+ def write_config_file(template_path, path, data)
367
+ file_contents = File.read(template_path)
334
368
  template = ERB.new(file_contents, :trim_mode => "-")
335
369
  config = template.result(OpenStruct.new(data).instance_eval { binding })
336
370
 
337
371
  FileUtils.mkdir_p(File.join(Dir.pwd, "config"))
338
- File.write(File.join(Dir.pwd, "config/appsignal.yml"), config)
372
+ File.write(path, config)
339
373
  end
340
374
 
341
375
  def new_config
@@ -35,6 +35,7 @@ module Appsignal
35
35
  def self.determine_env(initial_env = nil)
36
36
  [
37
37
  initial_env,
38
+ ENV.fetch("_APPSIGNAL_CONFIG_FILE_ENV", nil), # PRIVATE ENV var used by the diagnose CLI
38
39
  ENV.fetch("APPSIGNAL_APP_ENV", nil),
39
40
  ENV.fetch("RAILS_ENV", nil),
40
41
  ENV.fetch("RACK_ENV", nil)
@@ -53,6 +54,9 @@ module Appsignal
53
54
  # Determine which root path AppSignal should initialize with.
54
55
  # @api private
55
56
  def self.determine_root_path
57
+ app_path_env_var = ENV.fetch("APPSIGNAL_APP_PATH", nil)
58
+ return app_path_env_var if app_path_env_var
59
+
56
60
  loader_defaults.reverse.each do |loader_defaults|
57
61
  root_path = loader_defaults[:root_path]
58
62
  return root_path if root_path
@@ -61,6 +65,26 @@ module Appsignal
61
65
  Dir.pwd
62
66
  end
63
67
 
68
+ # @api private
69
+ class Context
70
+ DSL_FILENAME = "config/appsignal.rb"
71
+
72
+ attr_reader :env, :root_path
73
+
74
+ def initialize(env: nil, root_path: nil)
75
+ @env = env
76
+ @root_path = root_path
77
+ end
78
+
79
+ def dsl_config_file
80
+ File.join(root_path, DSL_FILENAME)
81
+ end
82
+
83
+ def dsl_config_file?
84
+ File.exist?(dsl_config_file)
85
+ end
86
+ end
87
+
64
88
  # @api private
65
89
  DEFAULT_CONFIG = {
66
90
  :activejob_report_errors => "all",
@@ -120,64 +144,67 @@ module Appsignal
120
144
  }.freeze
121
145
 
122
146
  # @api private
123
- ENV_STRING_KEYS = {
124
- "APPSIGNAL_ACTIVEJOB_REPORT_ERRORS" => :activejob_report_errors,
125
- "APPSIGNAL_APP_NAME" => :name,
126
- "APPSIGNAL_BIND_ADDRESS" => :bind_address,
127
- "APPSIGNAL_CA_FILE_PATH" => :ca_file_path,
128
- "APPSIGNAL_HOSTNAME" => :hostname,
129
- "APPSIGNAL_HOST_ROLE" => :host_role,
130
- "APPSIGNAL_HTTP_PROXY" => :http_proxy,
131
- "APPSIGNAL_LOG" => :log,
132
- "APPSIGNAL_LOG_LEVEL" => :log_level,
133
- "APPSIGNAL_LOG_PATH" => :log_path,
134
- "APPSIGNAL_LOGGING_ENDPOINT" => :logging_endpoint,
135
- "APPSIGNAL_PUSH_API_ENDPOINT" => :endpoint,
136
- "APPSIGNAL_PUSH_API_KEY" => :push_api_key,
137
- "APPSIGNAL_SIDEKIQ_REPORT_ERRORS" => :sidekiq_report_errors,
138
- "APPSIGNAL_STATSD_PORT" => :statsd_port,
139
- "APPSIGNAL_WORKING_DIRECTORY_PATH" => :working_directory_path,
140
- "APP_REVISION" => :revision
147
+ STRING_OPTIONS = {
148
+ :activejob_report_errors => "APPSIGNAL_ACTIVEJOB_REPORT_ERRORS",
149
+ :name => "APPSIGNAL_APP_NAME",
150
+ :bind_address => "APPSIGNAL_BIND_ADDRESS",
151
+ :ca_file_path => "APPSIGNAL_CA_FILE_PATH",
152
+ :hostname => "APPSIGNAL_HOSTNAME",
153
+ :host_role => "APPSIGNAL_HOST_ROLE",
154
+ :http_proxy => "APPSIGNAL_HTTP_PROXY",
155
+ :log => "APPSIGNAL_LOG",
156
+ :log_level => "APPSIGNAL_LOG_LEVEL",
157
+ :log_path => "APPSIGNAL_LOG_PATH",
158
+ :logging_endpoint => "APPSIGNAL_LOGGING_ENDPOINT",
159
+ :endpoint => "APPSIGNAL_PUSH_API_ENDPOINT",
160
+ :push_api_key => "APPSIGNAL_PUSH_API_KEY",
161
+ :sidekiq_report_errors => "APPSIGNAL_SIDEKIQ_REPORT_ERRORS",
162
+ :statsd_port => "APPSIGNAL_STATSD_PORT",
163
+ :working_directory_path => "APPSIGNAL_WORKING_DIRECTORY_PATH",
164
+ :revision => "APP_REVISION"
141
165
  }.freeze
166
+
142
167
  # @api private
143
- ENV_BOOLEAN_KEYS = {
144
- "APPSIGNAL_ACTIVE" => :active,
145
- "APPSIGNAL_ENABLE_ALLOCATION_TRACKING" => :enable_allocation_tracking,
146
- "APPSIGNAL_ENABLE_AT_EXIT_REPORTER" => :enable_at_exit_reporter,
147
- "APPSIGNAL_ENABLE_HOST_METRICS" => :enable_host_metrics,
148
- "APPSIGNAL_ENABLE_MINUTELY_PROBES" => :enable_minutely_probes,
149
- "APPSIGNAL_ENABLE_STATSD" => :enable_statsd,
150
- "APPSIGNAL_ENABLE_NGINX_METRICS" => :enable_nginx_metrics,
151
- "APPSIGNAL_ENABLE_GVL_GLOBAL_TIMER" => :enable_gvl_global_timer,
152
- "APPSIGNAL_ENABLE_GVL_WAITING_THREADS" => :enable_gvl_waiting_threads,
153
- "APPSIGNAL_ENABLE_RAILS_ERROR_REPORTER" => :enable_rails_error_reporter,
154
- "APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION" =>
155
- :enable_rake_performance_instrumentation,
156
- "APPSIGNAL_FILES_WORLD_ACCESSIBLE" => :files_world_accessible,
157
- "APPSIGNAL_INSTRUMENT_HTTP_RB" => :instrument_http_rb,
158
- "APPSIGNAL_INSTRUMENT_NET_HTTP" => :instrument_net_http,
159
- "APPSIGNAL_INSTRUMENT_REDIS" => :instrument_redis,
160
- "APPSIGNAL_INSTRUMENT_SEQUEL" => :instrument_sequel,
161
- "APPSIGNAL_RUNNING_IN_CONTAINER" => :running_in_container,
162
- "APPSIGNAL_SEND_ENVIRONMENT_METADATA" => :send_environment_metadata,
163
- "APPSIGNAL_SEND_PARAMS" => :send_params,
164
- "APPSIGNAL_SEND_SESSION_DATA" => :send_session_data
168
+ BOOLEAN_OPTIONS = {
169
+ :active => "APPSIGNAL_ACTIVE",
170
+ :enable_allocation_tracking => "APPSIGNAL_ENABLE_ALLOCATION_TRACKING",
171
+ :enable_at_exit_reporter => "APPSIGNAL_ENABLE_AT_EXIT_REPORTER",
172
+ :enable_host_metrics => "APPSIGNAL_ENABLE_HOST_METRICS",
173
+ :enable_minutely_probes => "APPSIGNAL_ENABLE_MINUTELY_PROBES",
174
+ :enable_statsd => "APPSIGNAL_ENABLE_STATSD",
175
+ :enable_nginx_metrics => "APPSIGNAL_ENABLE_NGINX_METRICS",
176
+ :enable_gvl_global_timer => "APPSIGNAL_ENABLE_GVL_GLOBAL_TIMER",
177
+ :enable_gvl_waiting_threads => "APPSIGNAL_ENABLE_GVL_WAITING_THREADS",
178
+ :enable_rails_error_reporter => "APPSIGNAL_ENABLE_RAILS_ERROR_REPORTER",
179
+ :enable_rake_performance_instrumentation =>
180
+ "APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION",
181
+ :files_world_accessible => "APPSIGNAL_FILES_WORLD_ACCESSIBLE",
182
+ :instrument_http_rb => "APPSIGNAL_INSTRUMENT_HTTP_RB",
183
+ :instrument_net_http => "APPSIGNAL_INSTRUMENT_NET_HTTP",
184
+ :instrument_redis => "APPSIGNAL_INSTRUMENT_REDIS",
185
+ :instrument_sequel => "APPSIGNAL_INSTRUMENT_SEQUEL",
186
+ :running_in_container => "APPSIGNAL_RUNNING_IN_CONTAINER",
187
+ :send_environment_metadata => "APPSIGNAL_SEND_ENVIRONMENT_METADATA",
188
+ :send_params => "APPSIGNAL_SEND_PARAMS",
189
+ :send_session_data => "APPSIGNAL_SEND_SESSION_DATA"
165
190
  }.freeze
191
+
166
192
  # @api private
167
- ENV_ARRAY_KEYS = {
168
- "APPSIGNAL_DNS_SERVERS" => :dns_servers,
169
- "APPSIGNAL_FILTER_METADATA" => :filter_metadata,
170
- "APPSIGNAL_FILTER_PARAMETERS" => :filter_parameters,
171
- "APPSIGNAL_FILTER_SESSION_DATA" => :filter_session_data,
172
- "APPSIGNAL_IGNORE_ACTIONS" => :ignore_actions,
173
- "APPSIGNAL_IGNORE_ERRORS" => :ignore_errors,
174
- "APPSIGNAL_IGNORE_LOGS" => :ignore_logs,
175
- "APPSIGNAL_IGNORE_NAMESPACES" => :ignore_namespaces,
176
- "APPSIGNAL_REQUEST_HEADERS" => :request_headers
193
+ ARRAY_OPTIONS = {
194
+ :dns_servers => "APPSIGNAL_DNS_SERVERS",
195
+ :filter_metadata => "APPSIGNAL_FILTER_METADATA",
196
+ :filter_parameters => "APPSIGNAL_FILTER_PARAMETERS",
197
+ :filter_session_data => "APPSIGNAL_FILTER_SESSION_DATA",
198
+ :ignore_actions => "APPSIGNAL_IGNORE_ACTIONS",
199
+ :ignore_errors => "APPSIGNAL_IGNORE_ERRORS",
200
+ :ignore_logs => "APPSIGNAL_IGNORE_LOGS",
201
+ :ignore_namespaces => "APPSIGNAL_IGNORE_NAMESPACES",
202
+ :request_headers => "APPSIGNAL_REQUEST_HEADERS"
177
203
  }.freeze
204
+
178
205
  # @api private
179
- ENV_FLOAT_KEYS = {
180
- "APPSIGNAL_CPU_COUNT" => :cpu_count
206
+ FLOAT_OPTIONS = {
207
+ :cpu_count => "APPSIGNAL_CPU_COUNT"
181
208
  }.freeze
182
209
 
183
210
  # @api private
@@ -210,8 +237,10 @@ module Appsignal
210
237
  # How to integrate AppSignal manually
211
238
  def initialize(
212
239
  root_path,
213
- env
240
+ env,
241
+ load_yaml_file: true
214
242
  )
243
+ @load_yaml_file = load_yaml_file
215
244
  @root_path = root_path.to_s
216
245
  @config_file_error = false
217
246
  @config_file = config_file
@@ -240,23 +269,46 @@ module Appsignal
240
269
  @system_config = detect_from_system
241
270
  merge(system_config)
242
271
 
243
- # Set defaults from loaders in reverse order so the first register
272
+ # Set defaults from loaders in reverse order so the first registered
244
273
  # loader's defaults overwrite all others
245
274
  self.class.loader_defaults.reverse.each do |loader_defaults|
275
+ options = config_hash
276
+ new_loader_defaults = {}
246
277
  defaults = loader_defaults[:options]
247
- @loaders_config.merge!(defaults.merge(
278
+ defaults.each do |option, value|
279
+ new_loader_defaults[option] =
280
+ if ARRAY_OPTIONS.key?(option)
281
+ # Merge arrays: new value first
282
+ value + options[option]
283
+ else
284
+ value
285
+ end
286
+ end
287
+ @loaders_config.merge!(new_loader_defaults.merge(
248
288
  :root_path => loader_defaults[:root_path],
249
289
  :env => loader_defaults[:env]
250
290
  ))
251
- merge(defaults)
291
+ merge(new_loader_defaults)
252
292
  end
253
293
 
254
294
  # Track origin of env
255
295
  @initial_config[:env] = @env
256
296
 
257
297
  # Load the config file if it exists
258
- @file_config = load_from_disk || {}
259
- merge(file_config)
298
+ if @load_yaml_file
299
+ @file_config = load_from_disk || {}
300
+ merge(file_config)
301
+ elsif yml_config_file?
302
+ # When in a `config/appsignal.rb` file and it detects a
303
+ # `config/appsignal.yml` file.
304
+ # Only logged and printed on `Appsignal.start`.
305
+ message = "Both a Ruby and YAML configuration file are found. " \
306
+ "The `config/appsignal.yml` file is ignored when the " \
307
+ "config is loaded from `config/appsignal.rb`. Move all config to " \
308
+ "the `config/appsignal.rb` file and remove the " \
309
+ "`config/appsignal.yml` file."
310
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(message)
311
+ end
260
312
 
261
313
  # Load config from environment variables
262
314
  @env_config = load_from_environment
@@ -421,6 +473,13 @@ module Appsignal
421
473
  config_hash.transform_values(&:freeze)
422
474
  end
423
475
 
476
+ # @api private
477
+ def yml_config_file?
478
+ return false unless config_file
479
+
480
+ File.exist?(config_file)
481
+ end
482
+
424
483
  private
425
484
 
426
485
  def logger
@@ -444,7 +503,7 @@ module Appsignal
444
503
  end
445
504
 
446
505
  def load_from_disk
447
- return if !config_file || !File.exist?(config_file)
506
+ return unless yml_config_file?
448
507
 
449
508
  read_options = YAML::VERSION >= "4.0.0" ? { :aliases => true } : {}
450
509
  configurations = YAML.load(ERB.new(File.read(config_file)).result, **read_options)
@@ -470,7 +529,7 @@ module Appsignal
470
529
  config = {}
471
530
 
472
531
  # Configuration with string type
473
- ENV_STRING_KEYS.each do |env_key, option|
532
+ STRING_OPTIONS.each do |option, env_key|
474
533
  env_var = ENV.fetch(env_key, nil)
475
534
  next unless env_var
476
535
 
@@ -478,7 +537,7 @@ module Appsignal
478
537
  end
479
538
 
480
539
  # Configuration with boolean type
481
- ENV_BOOLEAN_KEYS.each do |env_key, option|
540
+ BOOLEAN_OPTIONS.each do |option, env_key|
482
541
  env_var = ENV.fetch(env_key, nil)
483
542
  next unless env_var
484
543
 
@@ -486,7 +545,7 @@ module Appsignal
486
545
  end
487
546
 
488
547
  # Configuration with array of strings type
489
- ENV_ARRAY_KEYS.each do |env_key, option|
548
+ ARRAY_OPTIONS.each do |option, env_key|
490
549
  env_var = ENV.fetch(env_key, nil)
491
550
  next unless env_var
492
551
 
@@ -494,7 +553,7 @@ module Appsignal
494
553
  end
495
554
 
496
555
  # Configuration with float type
497
- ENV_FLOAT_KEYS.each do |env_key, option|
556
+ FLOAT_OPTIONS.each do |option, env_key|
498
557
  env_var = ENV.fetch(env_key, nil)
499
558
  next unless env_var
500
559
 
@@ -550,7 +609,20 @@ module Appsignal
550
609
  @config.env
551
610
  end
552
611
 
553
- Appsignal::Config::ENV_STRING_KEYS.each_value do |option|
612
+ # Returns true if the given environment name matches the loaded
613
+ # environment name.
614
+ #
615
+ # @param given_env [String, Symbol]
616
+ # @return [TrueClass, FalseClass]
617
+ def env?(given_env)
618
+ env == given_env.to_s
619
+ end
620
+
621
+ def activate_if_environment(*envs)
622
+ self.active = envs.map(&:to_s).include?(env)
623
+ end
624
+
625
+ Appsignal::Config::STRING_OPTIONS.each_key do |option|
554
626
  define_method(option) do
555
627
  fetch_option(option)
556
628
  end
@@ -560,7 +632,7 @@ module Appsignal
560
632
  end
561
633
  end
562
634
 
563
- Appsignal::Config::ENV_BOOLEAN_KEYS.each_value do |option|
635
+ Appsignal::Config::BOOLEAN_OPTIONS.each_key do |option|
564
636
  define_method(option) do
565
637
  fetch_option(option)
566
638
  end
@@ -570,7 +642,7 @@ module Appsignal
570
642
  end
571
643
  end
572
644
 
573
- Appsignal::Config::ENV_ARRAY_KEYS.each_value do |option|
645
+ Appsignal::Config::ARRAY_OPTIONS.each_key do |option|
574
646
  define_method(option) do
575
647
  fetch_option(option)
576
648
  end
@@ -580,7 +652,7 @@ module Appsignal
580
652
  end
581
653
  end
582
654
 
583
- Appsignal::Config::ENV_FLOAT_KEYS.each_value do |option|
655
+ Appsignal::Config::FLOAT_OPTIONS.each_key do |option|
584
656
  define_method(option) do
585
657
  fetch_option(option)
586
658
  end
@@ -80,7 +80,7 @@ module Appsignal
80
80
 
81
81
  # Logging methods
82
82
  attach_function :appsignal_log,
83
- [:appsignal_string, :int32, :appsignal_string, :pointer],
83
+ [:appsignal_string, :int32, :int32, :appsignal_string, :pointer],
84
84
  :void
85
85
 
86
86
  # Transaction methods
@@ -273,10 +273,11 @@ module Appsignal
273
273
  make_ruby_string state if state[:len] > 0
274
274
  end
275
275
 
276
- def log(group, level, message, attributes)
276
+ def log(group, level, format, message, attributes)
277
277
  appsignal_log(
278
278
  make_appsignal_string(group),
279
279
  level,
280
+ format,
280
281
  make_appsignal_string(message),
281
282
  attributes.pointer
282
283
  )
@@ -556,11 +556,20 @@ module Appsignal
556
556
 
557
557
  # Mark the parameters sample data to be set as an empty value.
558
558
  #
559
- # @api private
560
- # @since 4.0.0
559
+ # Use this helper to unset request parameters / background job arguments
560
+ # and not report any for this transaction.
561
+ #
562
+ # If parameters would normally be added by AppSignal instrumentations of
563
+ # libraries, these parameters will not be added to the Transaction.
564
+ #
565
+ # Calling {#add_params} after this helper will add new parameters to the
566
+ # transaction.
567
+ #
568
+ # @since 4.2.0
561
569
  # @return [void]
562
570
  #
563
- # @see Helpers::Instrumentation#set_empty_params!
571
+ # @see Transaction#set_empty_params!
572
+ # @see Transaction#set_params_if_nil
564
573
  def set_empty_params!
565
574
  return unless active?
566
575
  return unless Appsignal::Transaction.current?
@@ -45,7 +45,8 @@ module Appsignal
45
45
  :root_path => Rails.root,
46
46
  :env => Rails.env,
47
47
  :name => Appsignal::Utils::RailsHelper.detected_rails_app_name,
48
- :log_path => Rails.root.join("log")
48
+ :log_path => Rails.root.join("log"),
49
+ :ignore_actions => ["Rails::HealthController#show"]
49
50
  )
50
51
  end
51
52
 
@@ -9,7 +9,11 @@ module Appsignal
9
9
  hanami_app_config = ::Hanami.app.config
10
10
  register_config_defaults(
11
11
  :root_path => hanami_app_config.root.to_s,
12
- :env => hanami_app_config.env
12
+ :env => hanami_app_config.env,
13
+ :ignore_errors => [
14
+ "Hanami::Router::NotAllowedError",
15
+ "Hanami::Router::NotFoundError"
16
+ ]
13
17
  )
14
18
  end
15
19
 
@@ -23,9 +27,12 @@ module Appsignal
23
27
  )
24
28
  hanami_app_config.middleware.use(Appsignal::Rack::HanamiMiddleware)
25
29
 
30
+ return unless Gem::Version.new(Hanami::VERSION) < Gem::Version.new("2.2.0")
31
+
26
32
  ::Hanami::Action.prepend Appsignal::Loaders::HanamiLoader::HanamiIntegration
27
33
  end
28
34
 
35
+ # Legacy instrumentation to set the action name in Hanami apps older than Hanami 2.2
29
36
  module HanamiIntegration
30
37
  def call(env)
31
38
  super
@@ -25,15 +25,18 @@ module Appsignal
25
25
  # Create a new logger instance
26
26
  #
27
27
  # @param group Name of the group for this logger.
28
- # @param level Log level to filter with
28
+ # @param level Minimum log level to report. Log lines below this level will be ignored.
29
+ # @param format Format to use to parse log line attributes.
30
+ # @param attributes Default attributes for all log lines.
29
31
  # @return [void]
30
- def initialize(group, level: INFO, format: PLAINTEXT)
32
+ def initialize(group, level: INFO, format: PLAINTEXT, attributes: {})
31
33
  raise TypeError, "group must be a string" unless group.is_a? String
32
34
 
33
35
  @group = group
34
36
  @level = level
35
37
  @format = format
36
38
  @mutex = Mutex.new
39
+ @default_attributes = attributes
37
40
  end
38
41
 
39
42
  # We support the various methods in the Ruby
@@ -156,8 +159,10 @@ module Appsignal
156
159
 
157
160
  private
158
161
 
162
+ attr_reader :default_attributes
163
+
159
164
  def add_with_attributes(severity, message, group, attributes)
160
- Thread.current[:appsignal_logger_attributes] = attributes
165
+ Thread.current[:appsignal_logger_attributes] = default_attributes.merge(attributes)
161
166
  add(severity, message, group)
162
167
  ensure
163
168
  Thread.current[:appsignal_logger_attributes] = nil
@@ -12,12 +12,25 @@ module Appsignal
12
12
 
13
13
  private
14
14
 
15
+ HANAMI_ACTION_INSTANCE = "hanami.action_instance"
16
+ ROUTER_PARAMS = "router.params"
17
+
15
18
  def add_transaction_metadata_after(transaction, request)
19
+ action_name = fetch_hanami_action(request.env)
20
+ transaction.set_action_if_nil(action_name) if action_name
16
21
  transaction.add_params { params_for(request) }
17
22
  end
18
23
 
19
24
  def params_for(request)
20
- ::Hanami::Action.params_class.new(request.env).to_h
25
+ request.env.fetch(ROUTER_PARAMS, nil)
26
+ end
27
+
28
+ def fetch_hanami_action(env)
29
+ # This env key is available in Hanami 2.2+
30
+ action_instance = env.fetch(HANAMI_ACTION_INSTANCE, nil)
31
+ return unless action_instance
32
+
33
+ action_instance.class.name
21
34
  end
22
35
  end
23
36
  end
@@ -641,7 +641,7 @@ module Appsignal
641
641
  end
642
642
 
643
643
  BACKTRACE_REGEX =
644
- %r{(?<gem>[\w-]+ \(.+\) )?(?<path>:?/?\w+?.+?):(?<line>:?\d+)(?<group>:in `(?<method>.+)')?$}.freeze # rubocop:disable Layout/LineLength
644
+ %r{(?<gem>[\w-]+ \(.+\) )?(?<path>:?/?\w+?.+?):(?<line>:?\d+)(?::in `(?<method>.+)')?$}.freeze
645
645
 
646
646
  def first_formatted_backtrace_line(error)
647
647
  backtrace = cleaned_backtrace(error.backtrace)
@@ -655,7 +655,6 @@ module Appsignal
655
655
  .merge("original" => first_line)
656
656
  .tap do |c|
657
657
  config = Appsignal.config
658
- c.delete("group") # Unused key, only for easier matching
659
658
  # Strip of whitespace at the end of the gem name
660
659
  c["gem"] = c["gem"]&.strip
661
660
  # Strip the app path from the path if present
@@ -667,6 +666,8 @@ module Appsignal
667
666
  end
668
667
  # Add revision for linking to the repository from the UI
669
668
  c["revision"] = config[:revision]
669
+ # Convert line number to an integer
670
+ c["line"] = c["line"].to_i
670
671
  end
671
672
  end
672
673
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "4.1.2"
4
+ VERSION = "4.2.0"
5
5
  end
data/lib/appsignal.rb CHANGED
@@ -94,7 +94,7 @@ module Appsignal
94
94
  # @since 0.7.0
95
95
  def start # rubocop:disable Metrics/AbcSize
96
96
  if ENV.fetch("_APPSIGNAL_DIAGNOSE", false)
97
- internal_logger.warn("Skipping start in diagnose context")
97
+ internal_logger.info("Skipping start in diagnose context")
98
98
  return
99
99
  end
100
100
 
@@ -103,6 +103,13 @@ module Appsignal
103
103
  return
104
104
  end
105
105
 
106
+ if config_file_context?
107
+ internal_logger.warn(
108
+ "Ignoring call to Appsignal.start in config file context."
109
+ )
110
+ return
111
+ end
112
+
106
113
  unless extension_loaded?
107
114
  internal_logger.info("Not starting AppSignal, extension is not loaded")
108
115
  return
@@ -110,9 +117,7 @@ module Appsignal
110
117
 
111
118
  internal_logger.debug("Loading AppSignal gem")
112
119
 
113
- @config ||= Config.new(Config.determine_root_path, Config.determine_env)
114
- @config.validate
115
-
120
+ _load_config!
116
121
  _start_logger
117
122
 
118
123
  if config.valid?
@@ -142,6 +147,41 @@ module Appsignal
142
147
  end
143
148
  end
144
149
 
150
+ # PRIVATE METHOD. DO NOT USE.
151
+ #
152
+ # @param env_var [String, NilClass] Used by diagnose CLI to pass through
153
+ # the environment CLI option value.
154
+ # @api private
155
+ def _load_config!(env_param = nil)
156
+ context = Appsignal::Config::Context.new(
157
+ :env => Config.determine_env(env_param),
158
+ :root_path => Config.determine_root_path
159
+ )
160
+ # If there's a config/appsignal.rb file
161
+ if context.dsl_config_file?
162
+ if config
163
+ # When calling `Appsignal.configure` from an app, not the
164
+ # `config/appsignal.rb` file, with also a Ruby config file present.
165
+ message = "The `Appsignal.configure` helper is called from within an " \
166
+ "app while a `#{context.dsl_config_file}` file is present. " \
167
+ "The `config/appsignal.rb` file is ignored when the " \
168
+ "config is loaded with `Appsignal.configure` from within an app. " \
169
+ "We recommend moving all config to the `config/appsignal.rb` file " \
170
+ "or the `Appsignal.configure` helper in the app."
171
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(message)
172
+ else
173
+ # Load it when no config is present
174
+ load_dsl_config_file(context.dsl_config_file, env_param)
175
+ end
176
+ else
177
+ # Load config if no config file was found and no config is present yet
178
+ # This will load the config/appsignal.yml file automatically
179
+ @config ||= Config.new(context.root_path, context.env)
180
+ end
181
+ # Validate the config, if present
182
+ config&.validate
183
+ end
184
+
145
185
  # Stop AppSignal's agent.
146
186
  #
147
187
  # Stops the AppSignal agent. Call this before the end of your program to
@@ -222,7 +262,7 @@ module Appsignal
222
262
  # # Or for the environment given as an argument
223
263
  # Appsignal.configure(:production)
224
264
  #
225
- # @param env [String, Symbol] The environment to load.
265
+ # @param env_param [String, Symbol] The environment to load.
226
266
  # @param root_path [String] The path to look the `config/appsignal.yml` config file in.
227
267
  # Defaults to the current working directory.
228
268
  # @yield [Config] Gives the {Config} instance to the block.
@@ -231,23 +271,41 @@ module Appsignal
231
271
  # @see Config
232
272
  # @see https://docs.appsignal.com/ruby/configuration.html Configuration guide
233
273
  # @see https://docs.appsignal.com/ruby/configuration/options.html Configuration options
234
- def configure(env = nil, root_path: nil)
274
+ def configure(env_param = nil, root_path: nil)
235
275
  if Appsignal.started?
236
276
  Appsignal.internal_logger
237
277
  .warn("AppSignal is already started. Ignoring `Appsignal.configure` call.")
238
278
  return
239
279
  end
240
280
 
241
- if config && ((env.nil? || config.env == env.to_s) &&
242
- (root_path.nil? || config.root_path == root_path))
281
+ root_path_param = root_path
282
+ if params_match_loaded_config?(env_param, root_path_param)
243
283
  config
244
284
  else
245
285
  @config = Config.new(
246
- root_path || Config.determine_root_path,
247
- Config.determine_env(env)
286
+ root_path_param || Config.determine_root_path,
287
+ Config.determine_env(env_param),
288
+ # If in the context of an `config/appsignal.rb` config file, do not
289
+ # load the `config/appsignal.yml` file.
290
+ # The `.rb` file is a replacement for the `.yml` file so it shouldn't
291
+ # load both.
292
+ :load_yaml_file => !config_file_context?
248
293
  )
249
294
  end
250
295
 
296
+ # When calling `Appsignal.configure` from a Rails initializer and a YAML
297
+ # file is present. We will not load the YAML file in the future.
298
+ if !config_file_context? && config.yml_config_file?
299
+ message = "The `Appsignal.configure` helper is called while a " \
300
+ "`config/appsignal.yml` file is present. In future versions the " \
301
+ "`config/appsignal.yml` file will be ignored when loading the " \
302
+ "config. We recommend moving all config to the " \
303
+ "`config/appsignal.rb` file, or the `Appsignal.configure` helper " \
304
+ "in Rails initializer file, and remove the " \
305
+ "`config/appsignal.yml` file."
306
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(message)
307
+ end
308
+
251
309
  config_dsl = Appsignal::Config::ConfigDSL.new(config)
252
310
  return unless block_given?
253
311
 
@@ -397,8 +455,68 @@ module Appsignal
397
455
  config&.active? && extension_loaded?
398
456
  end
399
457
 
458
+ # @api private
459
+ def dsl_config_file_loaded?
460
+ defined?(@dsl_config_file_loaded) ? true : false
461
+ end
462
+
400
463
  private
401
464
 
465
+ def params_match_loaded_config?(env_param, root_path_param)
466
+ # No config present: can't match any config
467
+ return false unless config
468
+
469
+ # Check if the params, if present, match the loaded config
470
+ (env_param.nil? || config.env == env_param.to_s) &&
471
+ (root_path_param.nil? || config.root_path == root_path_param)
472
+ end
473
+
474
+ # Load the `config/appsignal.rb` config file, if present.
475
+ #
476
+ # If the config file has already been loaded once and it's trying to be
477
+ # loaded more than once, which should never happen, it will not do
478
+ # anything.
479
+ def load_dsl_config_file(path, env_param = nil)
480
+ return if defined?(@dsl_config_file_loaded)
481
+
482
+ begin
483
+ ENV["_APPSIGNAL_CONFIG_FILE_CONTEXT"] = "true"
484
+ ENV["_APPSIGNAL_CONFIG_FILE_ENV"] = env_param if env_param
485
+ @dsl_config_file_loaded = true
486
+ require path
487
+ rescue => error
488
+ @config_file_error = error
489
+ message = "Not starting AppSignal because an error occurred while " \
490
+ "loading the AppSignal config file.\n" \
491
+ "File: #{path.inspect}\n" \
492
+ "#{error.class.name}: #{error}"
493
+ Kernel.warn "appsignal ERROR: #{message}"
494
+ internal_logger.error "#{message}\n#{error.backtrace.join("\n")}"
495
+ ensure
496
+ unless Appsignal.config
497
+ # Ensure _a config object_ is present, even if something went wrong
498
+ # loading it or the file is empty. In this config file context, see
499
+ # the context env vars, it will intentionally not load the YAML file.
500
+ Appsignal.configure
501
+
502
+ # Disable if no config was loaded from the file but it is present
503
+ config[:active] = false
504
+ end
505
+
506
+ # Disable on config file error
507
+ config[:active] = false if defined?(@config_file_error)
508
+
509
+ ENV.delete("_APPSIGNAL_CONFIG_FILE_CONTEXT")
510
+ ENV.delete("_APPSIGNAL_CONFIG_FILE_ENV")
511
+ end
512
+ end
513
+
514
+ # Returns true if we're currently in the `config/appsignal.rb` file
515
+ # context.
516
+ def config_file_context?
517
+ ENV.fetch("_APPSIGNAL_CONFIG_FILE_CONTEXT", nil) == "true"
518
+ end
519
+
402
520
  def start_internal_stdout_logger
403
521
  @internal_logger = Appsignal::Utils::IntegrationLogger.new($stdout)
404
522
  internal_logger.formatter = log_formatter("appsignal")
@@ -0,0 +1,22 @@
1
+ # AppSignal Ruby gem configuration
2
+ # Visit our documentation for a list of all available configuration options.
3
+ # https://docs.appsignal.com/ruby/configuration/options.html
4
+ Appsignal.configure do |config|
5
+ config.activate_if_environment(<%= environments.map(&:inspect).join(", ") %>)
6
+ config.name = <%= app_name.inspect %>
7
+ # The application's Push API key
8
+ # We recommend removing this line and setting this option with the
9
+ # APPSIGNAL_PUSH_API_KEY environment variable instead.
10
+ # https://docs.appsignal.com/ruby/configuration/options.html#option-push_api_key
11
+ config.push_api_key = "<%= push_api_key %>"
12
+
13
+ # Configure actions that should not be monitored by AppSignal.
14
+ # For more information see our docs:
15
+ # https://docs.appsignal.com/ruby/configuration/ignore-actions.html
16
+ # config.ignore_actions << "ApplicationController#isup"
17
+
18
+ # Configure errors that should not be recorded by AppSignal.
19
+ # For more information see our docs:
20
+ # https://docs.appsignal.com/ruby/configuration/ignore-errors.html
21
+ # config.ignore_errors << "MyCustomError"
22
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.2
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Beekman
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-10-04 00:00:00.000000000 Z
13
+ date: 2024-11-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: logger
@@ -284,6 +284,7 @@ files:
284
284
  - lib/appsignal/version.rb
285
285
  - lib/puma/plugin/appsignal.rb
286
286
  - lib/sequel/extensions/appsignal_integration.rb
287
+ - resources/appsignal.rb.erb
287
288
  - resources/appsignal.yml.erb
288
289
  - resources/cacert.pem
289
290
  homepage: https://github.com/appsignal/appsignal-ruby
@@ -312,7 +313,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
312
313
  - !ruby/object:Gem::Version
313
314
  version: '0'
314
315
  requirements: []
315
- rubygems_version: 3.5.14
316
+ rubygems_version: 3.3.7
316
317
  signing_key:
317
318
  specification_version: 4
318
319
  summary: Logs performance and exception data from your app to appsignal.com