loggun 0.1.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a8a4d4015105e9d55b653cab3305ab2b1ddeeda0e1429bd5e2449c5841771fe
4
- data.tar.gz: e6a84389338458849f87dfb2ffcdea13403537553fa547b170c4debb5901f433
3
+ metadata.gz: cfd41231567df2c15cca3c6ba500fc8228dcf03ac808b2adb452385be59d4217
4
+ data.tar.gz: 86c26424200b7c443a4160770d7b3f0d22490db5e0ac3c41fffdd2dadd795d9e
5
5
  SHA512:
6
- metadata.gz: f10eb810cb421dde460b1c97c777496447d22197dfdbf35bf6eae341a1b9b2a6270044135887a062882c0f8bf4ccc21efbfe3231598ee7f060ca5be220385a6f
7
- data.tar.gz: 3362704777d4d6814ba58e1a72aee945d5f1f8105d03ff20930e3ecd02d559d5878f90681a77aefd14231aef67dbb79b41cd1883a5cbc6e54a8fa3817c1a49c9
6
+ metadata.gz: '058933cfb04111fe6f0f106e97efde068932b575bfc2be6bdfee0f419db586b07e0a11025eba01b65d12f71a9ef8121dc88e4c53dc39037cd95d5ee6d1ccd90b'
7
+ data.tar.gz: ebd06ae4867bb4b8cc03fa0ef1815ca73f58af294fab484f3f1207c01d3b4c305cfaa442a6b82771524a909fdb88cb68a8421c760ba8099731957a158c910858
@@ -3,8 +3,6 @@ sudo: false
3
3
  language: ruby
4
4
  cache: bundler
5
5
  rvm:
6
- - 2.3.8
7
- - 2.4.6
8
6
  - 2.5.5
9
7
  - 2.6.5
10
8
  before_install: gem install bundler
@@ -0,0 +1,36 @@
1
+ # Changelog
2
+
3
+ ## 0.4.1 - 2020-07-28
4
+ * fixes
5
+ * fill type with class name for empty `log_entity_name`
6
+
7
+ ## 0.4.0 - 2020-06-02
8
+ * fixes
9
+ * fix key_value join character to space
10
+ * fix dummy dependency alerts
11
+ * features
12
+ * add new const MESSAGE_FORMATS and test for checking the value of message_format
13
+ * add check message_format
14
+ * boolean flag replace with a whitelist and create method for generating a message
15
+ * added ability to log messages format k=v
16
+
17
+ ## 0.3.1 - 2020-04-21
18
+ * fixes
19
+ * fix error "modify frozen String" for class name in helpers
20
+
21
+ ## 0.3.0 - 2020-04-17
22
+ * fixes
23
+ * make public #generate_log_transaction_id in helper
24
+ * removed incoming http modifier
25
+
26
+ ## 0.2.0 - 2020-04-13
27
+ * fixes
28
+ * fix Readme with active_record modifier
29
+ * fix except option for helper #log_options
30
+ * refactor helpers #log_type
31
+ * fix helper define log_methods caller
32
+ * improve stability of helpers
33
+ * features
34
+ * remove legacy agent from default log pattern
35
+ * new active record modifier
36
+ * improve sidekiq modifier for difference versions
data/README.md CHANGED
@@ -1,37 +1,70 @@
1
1
  # Loggun
2
2
 
3
- [![Sponsored by FunBox](https://funbox.ru/badges/sponsored_by_funbox_compact.svg)](https://funbox.ru)
4
-
5
3
  [![Gem Version](https://badge.fury.io/rb/loggun.svg)](https://badge.fury.io/rb/loggun)
6
4
  [![Build Status](https://travis-ci.org/funbox/loggun.svg?branch=master)](https://travis-ci.org/funbox/loggun)
7
5
 
8
- ## Описание
9
- Loggun - это гем, позволяющий привести все логи приложения к единому формату
6
+ Приводит логи приложения к единому формату.
7
+
8
+ ## Содержание
9
+
10
+ - [Установка](#установка)
11
+ - [Использование](#использование)
12
+ - [Конфигурация](#конфигурация)
13
+ - [Настройки](#настройки)
14
+ - [Модификаторы](#модификаторы)
15
+ - [Rails модификатор](#rails-модификатор)
16
+ - [Active Record модификатор](#active-record-модификатор)
17
+ - [Sidekiq модификатор](#sidekiq-модификатор)
18
+ - [Clockwork модификатор](#clockwork-модификатор)
19
+ - [Модификатор исходящих HTTP-запросов](#модификатор-исходящих-http-запросов)
20
+ - [Модификатор входящих запросов в Rails](#модификатор-входящих-запросов-в-rails)
21
+ - [Пользовательские модификаторы](#пользовательские-модификаторы)
22
+ - [Хелперы](#хелперы)
10
23
 
11
24
  ## Установка
12
25
 
13
- Чтобы установить гем, добавьте в ваш Gemfile:
26
+ Чтобы установить гем, добавьте его в Gemfile:
14
27
 
15
28
  ```ruby
16
29
  gem 'loggun'
17
30
  ```
18
31
 
19
- И выполните команду :
32
+ И выполните команду:
20
33
 
21
- $ bundle
34
+ ```bash
35
+ $ bundle
36
+ ```
22
37
 
23
38
  ## Использование
24
39
 
25
- ### Конфигурация
26
- Для успешной конфигурации гема необходимо подгружать файл при инициализации вашего приложения.
40
+ Loggun можно использовать как обертку для вашего `logger`. Для этого необходимо передать
41
+ ему инстанс логгера и настроить его `formatter`:
42
+
43
+ ```ruby
44
+ Loggun.logger = Rails.logger
45
+ Loggun.logger.formatter = Loggun::Formatter.new
46
+ ```
47
+
48
+ Теперь можно использовать Loggun для логирования в стандартизированном формате:
49
+
50
+ ```ruby
51
+ Loggun.info('http_request.api.request', user_id: current_user.id)
52
+ #=> 2020-04-11T22:35:04.225+03:00 - 170715 INFO http_request.api.request - {"user_id": 5465}
53
+ ...
54
+ Loggun.info('http_request.api.response', user_id: current_user.id, success: true)
55
+ #=> 2020-04-11T22:35:04.225+03:00 - 170715 INFO http_request.api.response - {"user_id": 5465, "success": true}
56
+ ```
57
+
58
+ ## Конфигурация
27
59
 
28
- `config/initializers/loggun.rb`
60
+ Конфигурацию гема необходимо производить при инициализации приложения. Например, так:
29
61
 
30
62
  ```ruby
31
63
  Loggun::Config.configure do |config|
32
64
  config.precision = :milliseconds
33
65
  config.pattern = '%{time} - %{pid} %{severity} %{type} %{tags_text} %{message}'
34
66
  config.parent_transaction_to_message = false
67
+ config.message_format = :json
35
68
 
36
69
  config.modifiers.rails = true
37
70
  config.modifiers.sidekiq = false
@@ -40,39 +73,130 @@ Loggun::Config.configure do |config|
40
73
  config.modifiers.outgoing_http = false
41
74
  end
42
75
  ```
43
- Все настройки являются опциональными.
44
- #### Настройки
45
- `precision` - точность отметок времени. По умолчанию - `milliseconds`. Может принимать одно из следующих значений: `sec`, `seconds`, `ms`, `millis`, `milliseconds`, `us`, `micros`, `microseconds`, `ns`, `nanos`, `nanoseconds`
46
76
 
47
- `pattern` - шаблон для формата вывода данных в лог. Доступные ключи: `time`, `pid`, `severity`, `type`, `tags_text`, `message`, `parent_transaction`
77
+ ### Настройки
78
+
79
+ Все настройки опциональны.
80
+
81
+ - `precision` — точность отметок времени.
82
+
83
+ Может принимать одно из следующих значений:
84
+ `sec`, `seconds`, `ms`, `millis`, `milliseconds`, `us`, `micros`, `microseconds`, `ns`, `nanos`, `nanoseconds`.
85
+
86
+ По умолчанию `milliseconds`.
87
+
88
+ - `pattern` — текстовый шаблон для формата вывода данных в лог.
89
+
90
+ Доступные ключи внутри шаблона: `time`, `pid`, `severity`, `type`, `tags_text`, `message`, `parent_transaction`.
91
+
92
+ - `parent_transaction_to_message` — если `true`, то значение `parent_transaction` будет добавлено в тело логируемого сообщения.
93
+
94
+ Ключ `parent_transaction` в шаблоне `pattern` можно использовать вне зависимости от значения этой настройки.
95
+
96
+ - `message_format` — формат переменной `message` в шаблоне `pattern`.
48
97
 
49
- `parent_transaction_to_message` - признак необходимости добавлять значение `parent_transaction` в тело логируемого сообщения.
50
- Вне зависимости от данной настройки можно использовать ключ `parent_transaction` в шаблоне `pattern`.
98
+ Доступные значения:
99
+
100
+ - `:json` — `message` логируется как JSON-строка;
101
+ - `:key_value` — `message` логируется в формате `key1=value1 key2=value2`.
102
+
103
+ - `modifiers` — модификаторы для переопределения формата логирования указанного компонента. См. «[Модификаторы](#модификаторы)».
51
104
 
52
- `modifiers` - модификаторы для переопределения формата логирования указанного компонента. См. далее.
105
+ ### Модификаторы
53
106
 
54
- #### Модификаторы
55
107
  Каждый модифкатор может быть активирован двумя равнозначными способами:
108
+
56
109
  ```ruby
57
110
  config.modifiers.rails = true
58
111
  ```
112
+
59
113
  или
114
+
60
115
  ```ruby
61
116
  config.modifiers.rails.enable = true
62
117
  ```
63
118
 
64
- `rails` - модифицирует форматирование логгера Rails.
119
+ качестве примера активируется Rails модификатор, но может быть любой другой.)
120
+
121
+ #### Rails модификатор
122
+
123
+ `config.modifier.rails`
124
+
125
+ Модифицирует форматирование логгера Rails.
126
+
127
+ #### Active Record модификатор
128
+
129
+ `config.modifier.active_record`
130
+
131
+ Добавляет (именно добавляет, а не модифицирует) нового подписчика на SQL-события.
132
+
133
+ SQL начинает дополнительно логироваться в Loggun формате, `severity` — `info`. Например:
134
+
135
+ ```text
136
+ 2020-04-12T20:08:52.913+03:00 - 487257 INFO storage.sql.query - {"sql":"SELECT 1","name":null,"duration":0.837}
137
+ ```
138
+
139
+ Дополнительные настройки:
140
+
141
+ - `log_subscriber_class_name` — имя класса, реализующего логирование SQL-события.
142
+
143
+ Необходим метод `#sql`. По умолчанию: `::Loggun::Modifiers::ActiveRecord::LoggunLogSubscriber`.
144
+
145
+ - `payload_keys` — необходимые ключи в полезной нарзуке. Используется в классе по умолчанию.
146
+
147
+ Доступные ключи: `%i[sql name duration source]`.
148
+
149
+ Пример:
150
+
151
+ ```ruby
152
+ Loggun::Config.configure do |config|
153
+ #...
154
+ config.modifiers.active_record.enable = true
155
+ config.modifiers.active_record.log_subscriber_class_name = 'MyApp::MyLogSubscriber'
156
+ config.modifiers.active_record.payload_keys = %i[sql duration]
157
+ #...
158
+ end
159
+ ```
160
+
161
+ #### Sidekiq модификатор
162
+
163
+ `config.modifiers.sidekiq`
164
+
165
+ Модифицирует форматирование логгера Sidekiq.
166
+
167
+ #### Clockwork модификатор
168
+
169
+ `config.modifiers.clockwork`
170
+
171
+ Модифицирует форматирование логгера Clockwork.
172
+
173
+ #### Модификатор исходящих HTTP-запросов
174
+
175
+ `config.modifiers.outgoing_http`
176
+
177
+ Добавляет логирование исходящих HTTP-запросов.
178
+ На данный момент поддерживаются только запросы, выполненные с помощью гема `HTTP`.
179
+
180
+ #### Модификатор входящих запросов в Rails
181
+
182
+ `config.modifiers.incoming_http`
183
+
184
+ Добавляет логирование входящих HTTP-запросов для контроллеров Rails.
185
+
186
+ Может иметь дополнительные настройки:
65
187
 
66
- `sidekiq` - модифицирует форматирование логгера Sidekiq.
188
+ - `controllers` массив имён базовых контроллеров, для которых необходимо добавить указанное логирование.
67
189
 
68
- `clockwork` - модифицирует форматирование логгера Clockwork.
190
+ - `success_condition` лямбда, определяющая, содержит ли успех ответ экшена.
69
191
 
70
- `outgoing_http` - добавляет логирование исходящих http запросов.
71
- На данный момент поддерживаются только запросы посредством гема `HTTP`.
192
+ Например: `-> { JSON.parse(response.body)['result'] == 'ok' }`
72
193
 
73
- `incoming_http` - добавляет логирование входящих http запросов для контроллеров Rails.
74
- Данный модификатор может иметь дополнительные настройки, которые устанавливаются следующим образом
75
- (приведены значения по умолчанию):
194
+ - `error_info` лямбда, позволяющая добавить в лог информацию об ошибке, содержащейся в неуспешном ответе экшена.
195
+
196
+ Например: `-> { JSON.parse(response.body)['error_code'] }`
197
+
198
+
199
+ Пример (приведены значения по умолчанию):
76
200
 
77
201
  ```ruby
78
202
  Loggun::Config.configure do |config|
@@ -85,25 +209,24 @@ Loggun::Config.configure do |config|
85
209
  end
86
210
  ```
87
211
 
88
- `controllers` - массив имён базовых контроллеров, для которых необходимо добавить указанное логирование.
212
+ **Для Rails 6 и выше данный модификатор может работать некорректно.**
89
213
 
90
- `success_condition` - лямбда, определяющая, содержит ли успех ответ экшена. Например `-> { JSON.parse(response.body)['result'] == 'ok' }`
214
+ В этом случае можно добавить в требуемый базовый контроллер строку:
91
215
 
92
- `error_info` - лямбда, позволяющая добавить в лог информацию об ошибке, содержащейся в неуспешном ответе экшена.
93
- Например `-> { JSON.parse(response.body)['error_code'] }`
94
-
95
- Для Rails 6 и выше данный модификатор может работать некорректно.
96
- В этом случае можно указать в требуемом базовом контроллере строку:
97
216
  ```ruby
98
217
  include Loggun::HttpHelpers
99
218
  ```
219
+
100
220
  Это делает настройки `enable` и `controllers` модификатора безсполезными,
101
- однако позволяет гарантированно логировать входящие http запросы.
221
+ однако позволяет гарантированно логировать входящие HTTP-запросы.
102
222
 
103
- Настройки `success_condition` и `error_info` продолжают использоваться и могу быть установлены требуемым образом.
223
+ Настройки `success_condition` и `error_info` продолжают использоваться и могут быть установлены требуемым образом.
224
+
225
+ #### Пользовательские модификаторы
104
226
 
105
227
  Помимо указанных модификаторов существует возможность добавить собственный.
106
- Необходимо уснаследовать его от `Loggun::Modifiers::Base` и указать в методе `apply` все необходимые действия.
228
+ Необходимо уснаследовать его от `Loggun::Modifiers::Base` и указать в методе `apply` все необходимые действия:
229
+
107
230
  ```ruby
108
231
  require 'sinatra/custom_logger'
109
232
 
@@ -113,7 +236,9 @@ class NewModifier < Loggun::Modifiers::Base
113
236
  end
114
237
  end
115
238
  ```
116
- Затем необходимо добавить его при конфигурации гема.
239
+
240
+ Затем необходимо добавить его при конфигурации гема:
241
+
117
242
 
118
243
  ```ruby
119
244
  Loggun::Config.configure do |config|
@@ -124,32 +249,45 @@ end
124
249
  ```
125
250
 
126
251
  ### Хелперы
127
- Подключение хелперов в класс позволяет использовать методы логирования `log_info` и `log_error`,
252
+
253
+ Подключение хэлперов в класс позволяет использовать методы логирования `log_info` и `log_error`,
128
254
  а также генерировать идентификатор транзации для каждого метода класса.
129
255
 
130
256
  Например:
257
+
131
258
  ```ruby
132
259
  class SomeClass
133
260
  include Loggun::Helpers
134
261
 
135
- log_options entity_action: :method_name, as_transaction: true
136
-
137
- def some_action
138
- log_info 'type_for_action', 'Information'
139
- bar
140
- end
262
+ log_options entity_action: :method_name, as_transaction: true, only: %i[download_data]
141
263
 
142
- def bar
143
- log_info 'type_for_bar', 'Bar information'
264
+ def download_data
265
+ log_info 'http_request', 'Information'
266
+ # ... make http request here
267
+ log_info 'http_response', success: true
144
268
  end
145
269
  end
146
270
  ```
147
- Даёт подобный вывод в лог:
271
+
272
+ При вызове `#download_data` будет следующий вывод в лог:
273
+
148
274
  ```
149
- 2020-03-04T16:58:38.207+05:00 - 28476 INFO type_for_action.some_class.some_action#msg_id_1583323118203 - {"value":["Information"]}
150
- 2020-03-04T16:58:38.208+05:00 - 28476 INFO type_for_bar.some_class.bar#msg_id_1583323118207 - {"value":["Bar information"],"parent_transaction":"class.geo_location__actual_location.fetch_input#msg_id_1583323118203"}
275
+ 2020-03-04T16:58:38.207+05:00 - 28476 INFO http_request.some_class.download_data#ffg5431_1583323118203 - {"message":["Information"]}
276
+ 2020-03-04T16:58:38.208+05:00 - 28476 INFO http_response.some_class.download_data#ffg5431_1583323118203 - {"success": true}
151
277
  ```
152
278
 
153
- ## License
279
+ **Важно**, что с хэлпером `log_options` необходимо использовать только методы вида `log_<severity>`.
280
+ Методы модуля `Loggun` не будут работать.
281
+
282
+ Список всех опций хэлпера `log_options`:
283
+
284
+ - `entity_name` — имя сущности метода, `string`;
285
+ - `entity_action` — действие сущности метода, `string`;
286
+ - `as_transaction` — добавлять ли уникальный ID транзакции для метода, `boolean`;
287
+ - `transaction_generator` — собственный генератор ID транзакции, `lambda`;
288
+ - `log_all_methods` — применять ли хэлпер ко всем методам, `boolean`;
289
+ - `only` — список методов, для которых необходимо применить хэлпер (работает только когда `log_all_methods = false`), `Array{Symbol}`;
290
+ - `except` — список методов, которые надо исключить для хэлпера, `Array{Symbol}`;
291
+ - `log_transaction_except` — список методов, логирование которых не нужно обогащать ID транзакции, `Array{Symbol}`.
154
292
 
155
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
293
+ [![Sponsored by FunBox](https://funbox.ru/badges/sponsored_by_funbox_centered.svg)](https://funbox.ru)
@@ -5,7 +5,6 @@ require 'loggun/config'
5
5
  require 'loggun/modifiers'
6
6
  require 'loggun/modifiers/base'
7
7
  require 'loggun/helpers'
8
- require 'loggun/http_helpers'
9
8
  require 'logger'
10
9
 
11
10
  module Loggun
@@ -6,21 +6,28 @@ module Loggun
6
6
  include Singleton
7
7
 
8
8
  DEFAULTS = {
9
- pattern: '%{time} - %{pid} %{severity} %{type} %{tags_text}%{agent} %{message}',
9
+ pattern: '%{time} - %{pid} %{severity} %{type} %{tags_text} %{message}',
10
10
  parent_transaction_to_message: true,
11
+ message_format: :json,
11
12
  precision: :milliseconds,
12
13
  incoming_http: {
13
14
  controllers: %w[ApplicationController],
14
15
  success_condition: -> { response.code == '200' },
15
16
  error_info: -> { nil }
17
+ },
18
+ active_record: {
19
+ log_subscriber_class_name: '::Loggun::Modifiers::ActiveRecord::LoggunLogSubscriber',
20
+ payload_keys: %i[sql name duration source]
16
21
  }
17
22
  }.freeze
18
- DEFAULT_MODIFIERS = %i[rails sidekiq clockwork incoming_http outgoing_http].freeze
23
+ DEFAULT_MODIFIERS = %i[rails active_record sidekiq clockwork outgoing_http].freeze
24
+ MESSAGE_FORMATS = %i[json key_value].freeze
19
25
 
20
26
  attr_accessor(
21
27
  :formatter,
22
28
  :pattern,
23
29
  :parent_transaction_to_message,
30
+ :message_format,
24
31
  :precision,
25
32
  :modifiers,
26
33
  :custom_modifiers
@@ -31,6 +38,7 @@ module Loggun
31
38
  @precision = DEFAULTS[:precision]
32
39
  @pattern = DEFAULTS[:pattern]
33
40
  @parent_transaction_to_message = DEFAULTS[:parent_transaction_to_message]
41
+ @message_format = DEFAULTS[:message_format]
34
42
  @modifiers = Loggun::OrderedOptions.new
35
43
  @custom_modifiers = []
36
44
  set_default_modifiers
@@ -40,6 +48,7 @@ module Loggun
40
48
  def configure(&block)
41
49
  block.call(instance)
42
50
  use_modifiers
51
+ check_config
43
52
  instance
44
53
  end
45
54
 
@@ -55,9 +64,15 @@ module Loggun
55
64
  instance.custom_modifiers.each(&:use)
56
65
  end
57
66
 
58
- def setup_formatter(app)
67
+ def check_config
68
+ return if MESSAGE_FORMATS.include? instance.message_format
69
+
70
+ raise FailureConfiguration, 'Unknown value for message_format'
71
+ end
72
+
73
+ def setup_formatter(app, formatter = nil)
59
74
  Loggun.logger = app.logger
60
- Loggun.logger.formatter = instance.formatter
75
+ Loggun.logger.formatter = formatter || instance.formatter
61
76
  end
62
77
  end
63
78
 
@@ -87,5 +102,7 @@ module Loggun
87
102
  3 # milliseconds
88
103
  end
89
104
  end
105
+
106
+ class FailureConfiguration < StandardError; end
90
107
  end
91
108
  end
@@ -5,7 +5,7 @@ module Loggun
5
5
  class Formatter
6
6
  DEFAULT_VALUE = '-'.freeze
7
7
 
8
- def call(severity, time, _program_name, message)
8
+ def call(severity, time, _program_name, message, loggun_type: nil)
9
9
  data = Hash.new(DEFAULT_VALUE)
10
10
  data[:time] = time.iso8601(config.timestamp_precision)
11
11
  data[:pid] = Process.pid
@@ -14,13 +14,13 @@ module Loggun
14
14
  if config.parent_transaction_to_message && parent_transaction
15
15
  message[:parent_transaction] = parent_transaction
16
16
  end
17
- message = JSON.generate(message)
17
+ message = format_message(message)
18
18
  end
19
19
 
20
20
  data[:message] = message.to_s.tr("\r\n", ' ').strip
21
21
  data[:severity] = severity&.to_s || 'INFO'
22
22
  data[:tags_text] = tags_text
23
- data[:type] = Loggun.type || DEFAULT_VALUE.dup
23
+ data[:type] = loggun_type || Loggun.type || DEFAULT_VALUE.dup
24
24
  data[:transaction_id] = Loggun.transaction_id
25
25
  data[:parent_transaction] = parent_transaction if parent_transaction
26
26
 
@@ -78,5 +78,16 @@ module Loggun
78
78
  def config
79
79
  Loggun::Config.instance
80
80
  end
81
+
82
+ def format_message(message)
83
+ if config.message_format == :json
84
+ JSON.generate(message)
85
+ elsif config.message_format == :key_value
86
+ message.map { |key, value| "#{key}=#{value}" }.join(' ')
87
+ else
88
+ warn('Unknown value for message_format')
89
+ JSON.generate(message)
90
+ end
91
+ end
81
92
  end
82
93
  end
@@ -3,53 +3,65 @@ require 'securerandom'
3
3
  module Loggun
4
4
  module Helpers
5
5
  SKIPPED_METHODS = %i[
6
- initialize loggun logger modified_methods
6
+ initialize loggun logger log_modified_methods loggun_init in_log_transaction with_log_type
7
7
  ].freeze
8
8
  DEFAULT_TYPE = 'class'.freeze
9
9
 
10
10
  def self.included(klass)
11
+ klass.extend(InitMethods)
12
+ klass.loggun_init
11
13
  klass.extend(ClassMethods)
12
- klass.init
13
14
  end
14
15
 
15
- module ClassMethods
16
+ module InitMethods
16
17
  attr_accessor(
17
18
  :with_log_transaction_id,
18
19
  :log_transaction_generator,
19
20
  :log_entity_name,
20
21
  :log_entity_action,
21
- :modified_methods,
22
- :generate_transaction_except
22
+ :log_modified_methods,
23
+ :log_skip_methods,
24
+ :log_only_methods,
25
+ :log_all_methods,
26
+ :log_transaction_except
23
27
  )
24
28
 
29
+ def loggun_init
30
+ @log_modified_methods = []
31
+ @log_all_methods = false
32
+ end
33
+ end
34
+
35
+ module ClassMethods
25
36
  def log_options(**options)
26
37
  @log_entity_name = options[:entity_name]
27
38
  @log_entity_action = options[:entity_action]
28
39
  @with_log_transaction_id = options[:as_transaction]
29
40
  @log_transaction_generator = options[:transaction_generator]
30
- @generate_transaction_except = options[:generate_transaction_except]&.map(&:to_sym)
31
- end
32
-
33
- def init
34
- @modified_methods = []
41
+ @log_transaction_except = options[:log_transaction_except]&.map(&:to_sym)
42
+ @log_skip_methods = options[:except]&.map(&:to_sym)
43
+ @log_only_methods = options[:only]&.map(&:to_sym)
44
+ @log_all_methods = options[:log_all_methods]
35
45
  end
36
46
 
37
47
  def method_added(method_name)
38
48
  super
39
- @modified_methods ||= []
40
- return if SKIPPED_METHODS.include?(method_name) ||
41
- modified_methods.include?(method_name)
49
+ @log_modified_methods ||= []
50
+
51
+ return if !log_all_methods && !log_only_methods&.include?(method_name)
52
+ return if log_skip_methods&.include?(method_name)
53
+ return if SKIPPED_METHODS.include?(method_name) || log_modified_methods.include?(method_name)
42
54
 
43
- modified_methods << method_name
55
+ log_modified_methods << method_name
44
56
  method = instance_method(method_name)
45
57
  undef_method(method_name)
46
58
 
47
59
  define_method(method_name) do |*args, &block|
48
- if self.class.generate_transaction_except&.include?(method_name.to_sym)
60
+ if self.class.log_transaction_except&.include?(method_name.to_sym)
49
61
  method.bind(self).call(*args, &block)
50
62
  else
51
63
  type = log_type(nil, method_name)
52
- in_transaction(type) do
64
+ in_log_transaction(type) do
53
65
  method.bind(self).call(*args, &block)
54
66
  end
55
67
  end
@@ -57,19 +69,15 @@ module Loggun
57
69
  end
58
70
  end
59
71
 
60
- %i[unknown fatal error warn info debug].each do |method|
61
- define_method("log_#{method}") do |*args, **attrs, &block|
72
+ %i[unknown fatal error warn info debug].each do |method_name|
73
+ define_method("log_#{method_name}") do |*args, **attrs, &block|
62
74
  type = args.shift
63
- next logger.send(method, type, &block) if args.empty? &&
64
- attrs.empty?
75
+ next logger.send(method_name, type, &block) if args.empty? && attrs.empty?
65
76
 
66
- method_name = caller_locations.first.label.split(' ').last
67
- type = log_type(type, method_name)
68
-
69
- if %i[fatal error].include?(method)
70
- methods = args.first.methods
71
- next unless methods.include?(:message) && methods.include?(:backtrace)
77
+ caller_method_name = caller_locations.first.label.split(' ').last
78
+ type = log_type(type, caller_method_name)
72
79
 
80
+ if %i[fatal error].include?(method_name) && %i[backtrace message].all? { |m| args.first.respond_to?(m) }
73
81
  error = args.shift
74
82
  attrs[:error] = { class: error.class, msg: error.message }
75
83
  if attrs[:hidden]
@@ -78,10 +86,10 @@ module Loggun
78
86
  attrs[:hidden] = { error: { backtrace: error.backtrace } }
79
87
  end
80
88
  end
81
- attrs[:value] = args unless args.empty?
89
+ attrs[:message] = args unless args.empty?
82
90
 
83
- with_type(type) do
84
- logger.send(method, **attrs, &block)
91
+ with_log_type(type) do
92
+ logger.send(method_name, **attrs, &block)
85
93
  end
86
94
  end
87
95
  end
@@ -98,7 +106,7 @@ module Loggun
98
106
  end
99
107
  end
100
108
 
101
- def in_transaction(current_type = nil, current_transaction_id = nil)
109
+ def in_log_transaction(current_type = nil, current_transaction_id = nil)
102
110
  current_transaction_id ||= generate_log_transaction_id
103
111
  previous_transaction_id = self.parent_transaction_id
104
112
  previous_type = self.parent_type
@@ -117,7 +125,7 @@ module Loggun
117
125
  self.parent_type = previous_type
118
126
  end
119
127
 
120
- def with_type(current_type)
128
+ def with_log_type(current_type)
121
129
  previous_type = self.type
122
130
  self.type = current_type
123
131
  yield
@@ -126,22 +134,32 @@ module Loggun
126
134
  end
127
135
 
128
136
  def log_type(type, method_name)
137
+ klass = self.class
129
138
  type ||= DEFAULT_TYPE.dup
130
139
  type_as_arr = type.split('.')
131
- klass = self.class
132
- log_entity_name = klass.log_entity_name if klass.respond_to?(:log_entity_name)
133
- log_entity_name ||= underscore(klass.name)
134
- type << ".#{log_entity_name}" if type_as_arr.size == 1
140
+
141
+ if type_as_arr.size == 1
142
+ log_entity_name = klass.log_entity_name if klass.respond_to?(:log_entity_name)
143
+
144
+ log_entity_name ||= underscore(klass.name.dup)
145
+ type_as_arr << log_entity_name
146
+ end
135
147
 
136
148
  return type unless klass.respond_to?(:log_entity_action)
137
149
 
138
- if klass.log_entity_action && type_as_arr.size < 3
139
- if klass.log_entity_action == :method_name && method_name
140
- type << ".#{method_name}"
141
- end
150
+ if klass.log_entity_action && klass.log_entity_action == :method_name && type_as_arr.size < 3 && method_name
151
+ type_as_arr << method_name
142
152
  end
143
153
 
144
- type
154
+ type_as_arr.join('.')
155
+ end
156
+
157
+ def generate_log_transaction_id
158
+ if self.class.log_transaction_generator
159
+ return self.class.log_transaction_generator.call(self)
160
+ end
161
+
162
+ "#{SecureRandom.uuid[0..7]}_#{DateTime.now.strftime('%Q')}"
145
163
  end
146
164
 
147
165
  private
@@ -162,15 +180,6 @@ module Loggun
162
180
  word
163
181
  end
164
182
 
165
- def generate_log_transaction_id
166
- return unless self.class.with_log_transaction_id
167
- if self.class.log_transaction_generator
168
- return self.class.log_transaction_generator.call
169
- end
170
-
171
- "#{SecureRandom.uuid[0..7]}_#{DateTime.now.strftime('%Q')}"
172
- end
173
-
174
183
  def logger
175
184
  Loggun.logger
176
185
  end
@@ -0,0 +1,22 @@
1
+ module Loggun
2
+ module Modifiers
3
+ class ActiveRecord < Loggun::Modifiers::Base
4
+ def apply
5
+ return unless defined?(::ActiveRecord) && defined?(::ActiveRecord::LogSubscriber)
6
+
7
+ subscriber_class_name = config.modifiers.active_record.log_subscriber_class_name
8
+ if subscriber_class_name == ::Loggun::Config::DEFAULTS[:active_record][:log_subscriber_class_name]
9
+ require 'loggun/modifiers/active_record/loggun_log_subscriber'
10
+ end
11
+ klass = Object.const_get(subscriber_class_name)
12
+
13
+ return klass.attach_to :active_record if klass.respond_to?(:attach_to)
14
+
15
+ Loggun.warn(
16
+ "Loggun: passed active_record.log_subscriber_class_name `#{subscriber_class_name}`" \
17
+ "must respond to #attached_to method"
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module Loggun
2
+ module Modifiers
3
+ class ActiveRecord
4
+ class LoggunLogSubscriber < ::ActiveRecord::LogSubscriber
5
+ def sql(event)
6
+ payload = event.payload
7
+ return if IGNORE_PAYLOAD_NAMES.include?(payload[:name]) || payload[:cached]
8
+
9
+ available_keys = ::Loggun::Config.instance.modifiers.active_record.payload_keys&.map { |k| k.downcase.to_sym }
10
+ data = { sql: payload[:sql], name: payload[:name], duration: event.duration.round(4) }
11
+ source = respond_to?(:extract_query_source_location) ? extract_query_source_location(caller) : nil
12
+ data.merge!(source: source.gsub(/(?<=\.rb)(.*)$/, '')) if source
13
+ if available_keys&.any?
14
+ data.each { |k, _| data.delete(k) unless available_keys.include?(k) }
15
+ end
16
+
17
+ Loggun.info 'storage.sql.query', data
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -14,6 +14,10 @@ module Loggun
14
14
  def apply
15
15
  raise NotImplementedError, 'You must implement #apply in your modifier.'
16
16
  end
17
+
18
+ def config
19
+ Loggun::Config.instance
20
+ end
17
21
  end
18
22
  end
19
23
  end
@@ -3,11 +3,21 @@ require 'sidekiq' if defined?(::Sidekiq)
3
3
  module Loggun
4
4
  module Modifiers
5
5
  class Sidekiq < Loggun::Modifiers::Base
6
+ MIN_SIDEKIQ_V = '4.0.0'.freeze
7
+
6
8
  def apply
7
- return unless defined?(::Sidekiq)
9
+ return unless defined?(::Sidekiq) && ::Sidekiq::VERSION >= MIN_SIDEKIQ_V
8
10
 
9
11
  ::Sidekiq.configure_server do |config|
10
- Loggun::Config.setup_formatter(config)
12
+ Loggun::Config.setup_formatter(config, LoggunFormatter.new)
13
+ end
14
+ end
15
+
16
+ if defined?(::Sidekiq)
17
+ if ::Sidekiq::VERSION >= '6.0.0'
18
+ require 'loggun/modifiers/sidekiq/sidekiq6'
19
+ else
20
+ require 'loggun/modifiers/sidekiq/sidekiq4'
11
21
  end
12
22
  end
13
23
  end
@@ -0,0 +1,39 @@
1
+ module Loggun
2
+ module Modifiers
3
+ class Sidekiq
4
+ class LoggunFormatter < ::Sidekiq::Logging::Pretty
5
+ def call(severity, time, _program_name, message)
6
+ message, loggun_type = prepared_message(message)
7
+ Loggun::Formatter.new.call(severity, time.utc, nil, message, loggun_type: loggun_type)
8
+ end
9
+
10
+ def prepared_message(message)
11
+ if %w[start].include?(message) || message[/^(done|fail):\s(.*)\ssec$/]
12
+ message, elapsed = split_msg_and_time(message)
13
+ loggun_type = "sidekiq.job.#{message}"
14
+ message = { tid: "#{Thread.current.object_id.to_s(36)}", context: context.strip }
15
+ message[:elapsed] = elapsed if elapsed
16
+ else
17
+ loggun_type = 'app.sidekiq.control'
18
+ message = { tid: Thread.current.object_id.to_s(36), message: message }
19
+ message.merge!(context: context) if context
20
+ end
21
+
22
+ [message, loggun_type]
23
+ end
24
+
25
+ def split_msg_and_time(message)
26
+ unless message[/^done:\s(.*)\ssec$/] || message[/^fail:\s(.*)\ssec$/]
27
+ return [message, nil]
28
+ end
29
+
30
+ msg_type = message[/^done:\s(.*)\ssec$/] ? 'done' : 'fail'
31
+
32
+ msg = message[/#{msg_type}:\s(.*)\ssec/] ? msg_type : message
33
+ elapsed = message.gsub(/#{msg_type}:\s/, '').gsub('sec', '').strip
34
+ [msg, elapsed]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ module Loggun
2
+ module Modifiers
3
+ class Sidekiq
4
+ class LoggunFormatter < ::Sidekiq::Logger::Formatters::Base
5
+ def call(severity, time, _program_name, message)
6
+ message, loggun_type = prepared_message(message)
7
+ Loggun::Formatter.new.call(severity, time.utc, nil, message, loggun_type: loggun_type)
8
+ end
9
+
10
+ def prepared_message(message)
11
+ if %w[start done fail].include?(message)
12
+ loggun_type = "sidekiq.job.#{message}"
13
+ message = "#{::Sidekiq.dump_json(ctx)}"
14
+ else
15
+ loggun_type = 'app.sidekiq.control'
16
+ message = { tid: tid, message: message }
17
+ message.merge!(context: format_context) if format_context
18
+ end
19
+
20
+ [message, loggun_type]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module Loggun
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.4.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loggun
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksandr Noskov
8
8
  - Sergey Nesterov
9
- autorequire:
9
+ autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-04-06 00:00:00.000000000 Z
12
+ date: 2020-07-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -134,6 +134,7 @@ files:
134
134
  - ".gitignore"
135
135
  - ".rspec"
136
136
  - ".travis.yml"
137
+ - CHANGELOG.md
137
138
  - Gemfile
138
139
  - LICENSE.txt
139
140
  - README.md
@@ -144,18 +145,20 @@ files:
144
145
  - lib/loggun/config.rb
145
146
  - lib/loggun/formatter.rb
146
147
  - lib/loggun/helpers.rb
147
- - lib/loggun/http_helpers.rb
148
148
  - lib/loggun/modifiers.rb
149
+ - lib/loggun/modifiers/active_record.rb
150
+ - lib/loggun/modifiers/active_record/loggun_log_subscriber.rb
149
151
  - lib/loggun/modifiers/base.rb
150
152
  - lib/loggun/modifiers/clockwork.rb
151
153
  - lib/loggun/modifiers/clockwork/manager.rb
152
154
  - lib/loggun/modifiers/clockwork/methods.rb
153
- - lib/loggun/modifiers/incoming_http.rb
154
155
  - lib/loggun/modifiers/outgoing_http.rb
155
156
  - lib/loggun/modifiers/outgoing_http/block_logger.rb
156
157
  - lib/loggun/modifiers/rails.rb
157
158
  - lib/loggun/modifiers/rails/railtie.rb
158
159
  - lib/loggun/modifiers/sidekiq.rb
160
+ - lib/loggun/modifiers/sidekiq/sidekiq4.rb
161
+ - lib/loggun/modifiers/sidekiq/sidekiq6.rb
159
162
  - lib/loggun/ordered_options.rb
160
163
  - lib/loggun/version.rb
161
164
  - loggun.gemspec
@@ -165,7 +168,7 @@ licenses:
165
168
  metadata:
166
169
  homepage_uri: https://github.com/funbox/loggun
167
170
  source_code_uri: https://github.com/funbox/loggun
168
- post_install_message:
171
+ post_install_message:
169
172
  rdoc_options: []
170
173
  require_paths:
171
174
  - lib
@@ -181,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
184
  version: '0'
182
185
  requirements: []
183
186
  rubygems_version: 3.0.6
184
- signing_key:
187
+ signing_key:
185
188
  specification_version: 4
186
189
  summary: Loggun
187
190
  test_files: []
@@ -1,48 +0,0 @@
1
- module Loggun
2
- module HttpHelpers
3
- def self.included(klass)
4
- klass.class_eval do
5
- around_action :log_http_actions
6
- end
7
- end
8
-
9
- private
10
-
11
- def log_http_actions
12
- log_action :start
13
- yield
14
- log_action :response
15
- rescue StandardError => e
16
- log_action :response, fail: e
17
- raise e
18
- end
19
-
20
- def log_action(action = :start, fail: nil)
21
- api = request.path[/\w+/]
22
- api_version = request.path[/v./]
23
- type = "http_request.#{api}.#{action}"
24
- data = { path: clean_pathname }
25
- data[:api_version] = api_version if api_version
26
-
27
- return Loggun.info type, data if action == :start
28
-
29
- success = fail.nil? && instance_exec(&modifier_config.success_condition)
30
- data[:success] = success
31
- unless success
32
- error = instance_exec(&modifier_config.error_info)
33
- data[:error] = error if error
34
- end
35
- Loggun.info type, data
36
- end
37
-
38
- def clean_pathname
39
- filtered_params = params.to_unsafe_h
40
- filtered_params.delete('action')
41
- request.path.gsub(/(#{filtered_params.values.join('|')})/, '').gsub(/\/api\/v./, '')
42
- end
43
-
44
- def modifier_config
45
- Loggun::Config.instance.modifiers.incoming_http
46
- end
47
- end
48
- end
@@ -1,16 +0,0 @@
1
- module Loggun
2
- module Modifiers
3
- class IncomingHttp < Loggun::Modifiers::Base
4
- def apply
5
- return unless defined?(ActionPack)
6
-
7
- controllers = Loggun::Config.instance.modifiers.incoming_http.controllers
8
- controllers.each do |controller|
9
- controller.constantize.class_eval do
10
- include Loggun::HttpHelpers
11
- end
12
- end
13
- end
14
- end
15
- end
16
- end