luna_park 0.11.6 → 0.12.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: 4db92d2cf17231ba0d96f4071b636b0bd91f98d7125b49268eeadd49cb712a76
4
- data.tar.gz: ea8d7bdaf649dc04f2343296ec24f234bfd1e5cd9110b93bc33a3d405a53d1cc
3
+ metadata.gz: 14e20ec6fc8a3a6e96958a184503dbc5850dbf74e14c8d5943514c32c264337b
4
+ data.tar.gz: 6b3860177c18140dc5ea8c3a1e5e26577a952597d6f9c8f820499b6128b29d97
5
5
  SHA512:
6
- metadata.gz: 63e880268e5a55561867f67f0a71b8804bbf36671c1fb2cc98cd3a17cdd84264e850fe739919864d3fc88e7f74056fabba73e89781a8766f4a239096e885278f
7
- data.tar.gz: 41e777a88fb0e95517ea2a5644454ffeedcbd902879040baa2149f82e63f48ef77779aef95088fe15b29e89ae33daf5163b0bdb9530a345b02ed506bb926026f
6
+ metadata.gz: 509321c66abc91c03bfd78cad59f8201c0961a064facf057bdd3db339747a4adb7eb227e09228bb486e8aa7261348d64fe554e034ba2d07b438d963ced03f004
7
+ data.tar.gz: 6c95a9de22724e65fd6afccc731b671aec2853e15bc7948a3ea395ac2735e1b30d0130773a8fccb9d6d714537cc0bd2ed44e3301b1e72de25f9cbab3ca4d4486
@@ -13,11 +13,11 @@ jobs:
13
13
  packages: write
14
14
 
15
15
  steps:
16
- - uses: actions/checkout@v2
16
+ - uses: actions/checkout@v3
17
17
  - name: Set up Ruby 2.5
18
- uses: actions/setup-ruby@v1
18
+ uses: ruby/setup-ruby@v1
19
19
  with:
20
- ruby-version: 2.5.x
20
+ ruby-version: '2.5'
21
21
 
22
22
  - name: Publish to GPR
23
23
  run: |
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .DS_Store
1
2
  /.idea/
2
3
  /.bundle/
3
4
  /.yardoc
data/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.12.0] - 2023-02-23
8
+ Changed
9
+ - Added `TaggedLog`
10
+
11
+ ## [0.11.7] - 2022-10-07
12
+ Changed
13
+ - Added `formatter` to `Notifiers::Log`. Using `format` in initializer is now deprecated.
14
+
7
15
  ## [0.11.6] - 2021-10-06
8
16
  Changed
9
17
  - in `UseCases::Scenario` now abstract method is `#perform` - not `call!`. It is backward-compatible change: `call!` still works as abstract, and public interface was not changed.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- luna_park (0.11.6)
4
+ luna_park (0.12.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -69,6 +69,29 @@ GEM
69
69
  multipart-post (>= 1.2, < 3)
70
70
  ruby2_keywords
71
71
  faraday-net_http (1.0.1)
72
+ ffi (1.15.5)
73
+ formatador (1.1.0)
74
+ guard (2.18.0)
75
+ formatador (>= 0.2.4)
76
+ listen (>= 2.7, < 4.0)
77
+ lumberjack (>= 1.0.12, < 2.0)
78
+ nenv (~> 0.1)
79
+ notiffany (~> 0.0)
80
+ pry (>= 0.13.0)
81
+ shellany (~> 0.0)
82
+ thor (>= 0.18.1)
83
+ guard-bundler (3.0.1)
84
+ bundler (>= 2.1, < 3)
85
+ guard (~> 2.2)
86
+ guard-compat (~> 1.1)
87
+ guard-compat (1.2.1)
88
+ guard-rspec (4.7.3)
89
+ guard (~> 2.1)
90
+ guard-compat (~> 1.1)
91
+ rspec (>= 2.99.0, < 4.0)
92
+ guard-rubocop (1.5.0)
93
+ guard (~> 2.0)
94
+ rubocop (< 2.0)
72
95
  hashdiff (1.0.1)
73
96
  http-accept (1.7.0)
74
97
  http-cookie (1.0.3)
@@ -77,12 +100,20 @@ GEM
77
100
  concurrent-ruby (~> 1.0)
78
101
  iniparse (1.5.0)
79
102
  json (2.3.1)
103
+ listen (3.8.0)
104
+ rb-fsevent (~> 0.10, >= 0.10.3)
105
+ rb-inotify (~> 0.9, >= 0.9.10)
106
+ lumberjack (1.2.8)
80
107
  method_source (1.0.0)
81
108
  mime-types (3.3.1)
82
109
  mime-types-data (~> 3.2015)
83
110
  mime-types-data (3.2020.0512)
84
111
  multipart-post (2.1.1)
112
+ nenv (0.3.0)
85
113
  netrc (0.11.0)
114
+ notiffany (0.1.3)
115
+ nenv (~> 0.1)
116
+ shellany (~> 0.0)
86
117
  overcommit (0.55.0)
87
118
  childprocess (>= 0.6.3, < 5)
88
119
  iniparse (~> 1.4)
@@ -98,6 +129,9 @@ GEM
98
129
  public_suffix (4.0.6)
99
130
  rainbow (3.0.0)
100
131
  rake (13.0.1)
132
+ rb-fsevent (0.11.2)
133
+ rb-inotify (0.10.1)
134
+ ffi (~> 1.0)
101
135
  regexp_parser (1.7.1)
102
136
  rest-client (2.1.0)
103
137
  http-accept (>= 1.7.0, < 2.0)
@@ -139,10 +173,12 @@ GEM
139
173
  sentry-ruby-core (4.2.1)
140
174
  concurrent-ruby
141
175
  faraday
176
+ shellany (0.0.1)
142
177
  simplecov (0.18.5)
143
178
  docile (~> 1.1)
144
179
  simplecov-html (~> 0.11)
145
180
  simplecov-html (0.12.2)
181
+ thor (1.2.1)
146
182
  timecop (0.9.1)
147
183
  unf (0.1.4)
148
184
  unf_ext
@@ -163,6 +199,10 @@ DEPENDENCIES
163
199
  byebug (~> 11.1)
164
200
  codecov (~> 0.2)
165
201
  dry-validation (~> 1.1)
202
+ guard
203
+ guard-bundler
204
+ guard-rspec
205
+ guard-rubocop
166
206
  i18n (~> 1.8)
167
207
  luna_park!
168
208
  overcommit (~> 0.55)
data/Guardfile ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ ignore(/
4
+ bin | public | node_modules | tmp | .git
5
+ /x)
6
+
7
+ guard :bundler do
8
+ watch('Gemfile')
9
+ watch('Gemfile.lock')
10
+ end
11
+
12
+ group :specs, halt_on_fail: true do
13
+ guard :rspec,
14
+ cmd: 'bundle exec rspec --color --format documentation',
15
+ all_after_pass: false,
16
+ all_on_start: false,
17
+ failed_mode: :keep do
18
+ require 'guard/rspec/dsl'
19
+ dsl = Guard::RSpec::Dsl.new(self)
20
+
21
+ # Feel free to open issues for suggestions and improvements
22
+
23
+ # RSpec files
24
+ rspec = dsl.rspec
25
+ watch(rspec.spec_helper) { rspec.spec_dir }
26
+ watch(rspec.spec_support) { rspec.spec_dir }
27
+ watch(rspec.spec_files)
28
+
29
+ # Ruby files
30
+ ruby = dsl.ruby
31
+ dsl.watch_spec_files_for(ruby.lib_files)
32
+
33
+ watch(%r{^config/(.+)\.rb$})
34
+
35
+ watch(%r{^spec/factories/(.+)\.rb$})
36
+ end
37
+
38
+ guard :rubocop, all_on_start: false, keep_failed: false do
39
+ watch(/.+\.rb$/)
40
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
41
+ end
42
+ end
@@ -113,6 +113,13 @@ module LunaPark
113
113
  # @return Hash
114
114
  attr_reader :cookies
115
115
 
116
+ # Exception of failed request
117
+ # Can be raised after call (without bang)
118
+ # Will be raised after call! (with bang)
119
+ #
120
+ # @return LunaPark::Errors::Http
121
+ attr_reader :exception
122
+
116
123
  # The request that actually initializes the current response
117
124
  #
118
125
  # @example
@@ -344,7 +351,7 @@ module LunaPark
344
351
  end
345
352
 
346
353
  # @example
347
- # request.to_h # => {
354
+ # response.to_h # => {
348
355
  # :code=>200,
349
356
  # :body=>"John Doe, Marry Ann",
350
357
  # :headers=>{}, :cookies=>{},
@@ -62,7 +62,7 @@ module LunaPark
62
62
  # @return [LunaPark::Http::Response]
63
63
  def call!
64
64
  call.tap do |response|
65
- raise Errors::Http.new(response.status, response: response) unless response.success?
65
+ raise response.exception unless response.exception.nil?
66
66
  end
67
67
  end
68
68
 
@@ -82,7 +82,7 @@ module LunaPark
82
82
  end
83
83
 
84
84
  def build_original_response(rest_response)
85
- Response.new(
85
+ build_response(
86
86
  body: rest_response&.body,
87
87
  code: rest_response&.code || 0,
88
88
  headers: rest_response&.headers,
@@ -92,11 +92,20 @@ module LunaPark
92
92
  end
93
93
 
94
94
  def build_timeout_response
95
- Response.new(code: 408, request: original_request)
95
+ build_response code: 408, request: original_request
96
96
  end
97
97
 
98
+ # ! 503 != ECONNREFUSED (https://www.rfc-editor.org/rfc/rfc7231#section-6.6.4)
98
99
  def build_unavailable_response
99
- Response.new(code: 503, request: original_request)
100
+ build_response code: 503, request: original_request
101
+ end
102
+
103
+ def build_response(code:, request:, **opts)
104
+ Response
105
+ .new(code: code, request: request, **opts)
106
+ .tap do |response|
107
+ response.exception = Errors::Http.new(response.status, response: response) unless response.success?
108
+ end
100
109
  end
101
110
  end
102
111
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'pp'
4
+ require 'json'
5
+
6
+ module LunaPark
7
+ module Notifiers
8
+ class Log
9
+ module Formatters
10
+ # Fomatter - callable object to format log messages. Out of the box there are four types:
11
+
12
+ # - SINGLE - output is a single line string message.
13
+ # notifier = LunaPark::Notifiers::Log.new(formatter: LunaPark::Notifiers::Log::Formatters::SINGLE)
14
+ # notifier.info('You hear', dog: 'wow', cats: {chloe: 'mow', timmy: 'mow'})
15
+ #
16
+ # # I, [2022-09-29T10:51:15.753646 #28763] INFO -- : String - You hear {:dog=>"wow", :cats=>{:chloe=>"mow", :timmy=>"mow"}}
17
+ #
18
+ SINGLE = lambda do |klass, message, details = {}|
19
+ details.empty? ? "#<#{klass}> #{message}" : "#<#{klass}> #{message} #{details}"
20
+ end
21
+
22
+ # - MULTILINE - this format may become more preferred for development mode.
23
+ # notifier = LunaPark::Notifiers::Log.new(formatter: LunaPark::Notifiers::Log::Formatters::MULTILINE)
24
+ # notifier.info('You hear', dog: 'wow', cat: {timmy:'purr'}, cow: 'moo', duck: 'quack', horse: 'yell' )
25
+ #
26
+ # # I, [2022-09-29T10:56:21.463211 #28763] INFO -- : {:class=>String,
27
+ # # :message=>"You hear",
28
+ # # :details=>
29
+ # # {:dog=>"wow",
30
+ # # :cat=>{:timmy=>"purr"},
31
+ # # :cow=>"moo",
32
+ # # :duck=>"quack",
33
+ # # :horse=>"yell"}}
34
+ MULTILINE = lambda do |klass, message, details = {}|
35
+ PP.pp({ class: klass, message: message, details: details }, '')
36
+ end
37
+
38
+ # - JSON - this format should be good choose for logger which be processed by external logger system
39
+ # notifier = LunaPark::Notifiers::Log.new(formatter: LunaPark::Notifiers::Log::Formatters::JSON)
40
+ # notifier.info('You hear', dog: 'wow', cats: {chloe: 'mow', timmy: 'mow'})
41
+ #
42
+ # # I, [2022-09-29T12:00:47.600052 #90508] INFO -- : {"class":"String", "message":"You hear",
43
+ # # "details":{"dog":"wow","cats":{"chloe":"mow","timmy":"mow"}}}
44
+ JSON = lambda do |klass, message, details = {}|
45
+ ::JSON.generate(class: klass, message: message, details: details)
46
+ end
47
+
48
+ # - PRETTY_JSON - pretty json output
49
+ # notifier = LunaPark::Notifiers::Log.new(formatter: LunaPark::Notifiers::Log::Formatters::PRETTY_JSON)
50
+ # notifier.info('You hear', dog: 'wow', cat: {timmy:'purr'}, cow: 'moo', duck: 'quack', horse: 'yell')
51
+ #
52
+ # # I, [2022-09-29T12:02:25.236301 #90508] INFO -- : {
53
+ # # "class": "String",
54
+ # # "message": "You hear",
55
+ # # "details": {
56
+ # # "dog": "wow",
57
+ # # "cat": {
58
+ # # "timmy": "purr"
59
+ # # },
60
+ # # "cow": "moo",
61
+ # # "duck": "quack",
62
+ # # "horse": "yell"
63
+ # # }
64
+ PRETTY_JSON = lambda do |klass, message, details = {}|
65
+ ::JSON.pretty_generate(class: klass, message: message, details: details)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
 
3
- require 'json'
4
- require 'pp'
5
3
  require 'logger'
6
4
  require 'luna_park/extensions/severity_levels'
5
+ require 'luna_park/notifiers/log/formatters'
7
6
  require 'luna_park/errors'
8
7
 
9
8
  module LunaPark
@@ -30,52 +29,14 @@ module LunaPark
30
29
  class Log
31
30
  include Extensions::SeverityLevels
32
31
 
33
- ENABLED_FORMATS = %i[single string json multiline pretty_json].freeze
34
-
35
- # Format of log output. Define output format of log message. It can be four types.
36
- #
37
- # - :single or :string - Then you will get single line string message. This is default
38
- # format for the logger.
39
- # notifier = LunaPark::Notifiers::Log.new(format: :single)
40
- # notifier.message('You hear', dog: 'wow', cats: {chloe: 'mow', timmy: 'mow'})
41
- #
42
- # # E, [2020-06-13T14:50:22 #20538] ERROR -- : You hear {:dog=>"wow", :cats=>{:chloe=>"mow", :timmy=>"mow"}}
43
- #
44
- # - :multiline - this format may become more preferred for development mode.
45
- # notifier = LunaPark::Notifiers::Log.new(format: :multiline)
46
- # notifier.message('You hear', dog: 'wow', cat: {timmy:'purr'}, cow: 'moo', duck: 'quack', horse: 'yell' )
47
- #
48
- # # E, [2020-06-13T18:24:37.592652 #22786] ERROR -- : {:message=>"You hear",
49
- # # :details=>
50
- # # {:dog=>"wow",
51
- # # :cat=>{:timmy=>"purr"},
52
- # # :cow=>"moo",
53
- # # :duck=>"quack",
54
- # # :horse=>"yell"}}
32
+ # Callable object to format log messages.
55
33
  #
56
- # - :json - this format should be good choose for logger which be processed by external logger system
57
- # notifier = LunaPark::Notifiers::Log.new(format: :json)
58
- # notifier.message('You hear', dog: 'wow', cats: {chloe: 'mow', timmy: 'mow'})
34
+ # pretty_formatter = ->(klass, message, details) { "#{klass} - #{message} - #{details}" }
35
+ # notifier = LunaPark::Notifiers::Log.new(formatter: pretty_formatter)
36
+ # notifier.info('You hear', dog: 'wow', cats: {chloe: 'mow', timmy: 'mow'})
37
+ # => I, [2022-09-29T10:51:15.753646 #28763] INFO -- : String - You hear - {:dog=>"wow", :cats=>{:chloe=>"mow", :timmy=>"mow"}}
59
38
  #
60
- # # E, [2020-06-13T18:28:07.567048 #22786] ERROR -- : {"message":"You hear","details":{"dog":"wow",
61
- # # "cats":{"chloe":"mow","timmy":"mow"}}}
62
- #
63
- # - :pretty_json - pretty json output
64
- # notifier = LunaPark::Notifiers::Log.new(format: :pretty_json)
65
- # notifier.message('You hear', dog: 'wow', cat: {timmy:'purr'}, cow: 'moo', duck: 'quack', horse: 'yell')
66
- #
67
- # # E, [2020-06-13T18:30:26.856084 #22786] ERROR -- : {
68
- # # "message": "You hear",
69
- # # "details": {
70
- # # "dog": "wow",
71
- # # "cat": {
72
- # # "timmy": "purr"
73
- # # },
74
- # # "cow": "moo",
75
- # # "duck": "quack",
76
- # # "horse": "yell"
77
- # # }
78
- attr_reader :format
39
+ attr_reader :formatter
79
40
 
80
41
  # Logger which used for output all notify. Should be instance of Logger class.
81
42
  # You can define it in two ways.
@@ -97,14 +58,18 @@ module LunaPark
97
58
 
98
59
  # Create new log notifier
99
60
  #
100
- # @param logger - Logger which used for output all notify see #logger
101
- # @param format - Format of notify message see #format
102
- # @param min_lvl - What level should a message be for it to be processed by a notifier
103
- def initialize(logger: nil, format: :single, min_lvl: :debug)
104
- raise ArgumentError, "Unknown format #{format}" unless ENABLED_FORMATS.include? format
105
-
61
+ # @param logger - Logger which used for output all notify see #logger
62
+ # @param formatter - Log messages formatter see #formatter
63
+ # @param format - Formatter name. Deprecated and will be removed in a future version
64
+ # @param min_lvl - What level should a message be for it to be processed by a notifier
65
+ def initialize(logger: nil, format: nil, formatter: nil, min_lvl: :debug)
106
66
  @logger = logger || self.class.default_logger
107
- @format = format
67
+ @formatter = formatter || Formatters::SINGLE
68
+ # @todo Remove format param in the future version
69
+ unless format.nil?
70
+ @formatter = formatter_by_name(format)
71
+ warn 'warn [DEPRECATION] `format` parameter is deprecated, use `formatter` instead'
72
+ end
108
73
  self.min_lvl = min_lvl
109
74
  end
110
75
 
@@ -160,13 +125,15 @@ module LunaPark
160
125
 
161
126
  def serialize(obj, **details)
162
127
  details = extend(details, with: obj)
163
- hash = { message: String(obj), details: details }
128
+ formatter.call(obj.class, String(obj), details)
129
+ end
164
130
 
165
- case format
166
- when :json then JSON.generate(hash)
167
- when :multiline then PP.pp(hash, '')
168
- when :pretty_json then JSON.pretty_generate(hash)
169
- else details.empty? ? String(obj) : "#{String(obj)} #{details}"
131
+ def formatter_by_name(name)
132
+ case name
133
+ when :json then Formatters::JSON
134
+ when :multiline then Formatters::MULTILINE
135
+ when :pretty_json then Formatters::PRETTY_JSON
136
+ else Formatters::SINGLE
170
137
  end
171
138
  end
172
139
  end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'luna_park/values/compound'
4
+
5
+ module LunaPark
6
+ module Notifiers
7
+ module TaggedLog
8
+ class Options < LunaPark::Values::Compound
9
+ attr_reader :default_tag, :app, :app_env, :instance, :min_lvl
10
+
11
+ def initialize(attrs = {})
12
+ logger_conf_error if config_incorrect?(attrs)
13
+ set_attributes attrs
14
+ end
15
+
16
+ # @param [Notifiers::Log::Options, Hash] other
17
+ # @return [Notifiers::Log::Options]
18
+ def merge!(other)
19
+ other = self.class.wrap(other)
20
+
21
+ self.default_tag ||= other.default_tag
22
+ self.app ||= other.app
23
+ self.app_env ||= other.app_env
24
+ self.instance ||= other.instance
25
+ self.min_lvl ||= other.min_lvl
26
+
27
+ self
28
+ end
29
+
30
+ def merge(other)
31
+ dup.merge!(other)
32
+ end
33
+
34
+ def to_h
35
+ {
36
+ default_tag: default_tag,
37
+ app: app,
38
+ app_env: app_env,
39
+ instance: instance,
40
+ min_lvl: min_lvl
41
+ }
42
+ end
43
+
44
+ private
45
+
46
+ def config_incorrect?(attrs)
47
+ return true if attrs.empty?
48
+
49
+ !%i[default_tag app app_env instance min_lvl].all? do |required_key|
50
+ attrs.keys.include?(required_key)
51
+ end
52
+ end
53
+
54
+ def logger_conf_error
55
+ raise ArgumentError, 'TaggedLog not properly configured'
56
+ end
57
+
58
+ def default_tag=(val)
59
+ logger_conf_error if val.nil? || val.empty?
60
+ logger_conf_error unless val.is_a?(String) || val.is_a?(Symbol)
61
+ @default_tag = val
62
+ end
63
+
64
+ def app=(val)
65
+ logger_conf_error if val.nil? || val.empty? || !val.is_a?(String)
66
+ @app = val
67
+ end
68
+
69
+ def app_env=(val)
70
+ logger_conf_error if val.nil? || val.empty? || !val.is_a?(String)
71
+ @app_env = val
72
+ end
73
+
74
+ def instance=(val)
75
+ logger_conf_error if val.nil? || val.empty? || !val.is_a?(String)
76
+ @instance = val
77
+ end
78
+
79
+ def min_lvl=(val)
80
+ logger_conf_error if val.nil? || val.empty?
81
+ logger_conf_error unless val.is_a?(String) || val.is_a?(Symbol)
82
+ @min_lvl = val.to_sym
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'json'
4
+
5
+ module LunaPark
6
+ module Notifiers
7
+ module TaggedLog
8
+ class TaggedFormatter < Logger::Formatter
9
+ attr_accessor :config
10
+
11
+ def call(severity, timestamp, _, msg, tags = nil)
12
+ payload = common_payload(severity, timestamp, tags)
13
+ .merge(msg_payload(msg[:original_msg]))
14
+
15
+ deep_merge!(payload, details_payload(msg[:details]))
16
+
17
+ ::JSON.generate(payload) << "\n"
18
+ end
19
+
20
+ private
21
+
22
+ def details_payload(hash)
23
+ details = hash.delete(:details)
24
+ payload = { details: hash }
25
+ deep_merge!(payload, { details: details }) unless details.nil?
26
+ payload
27
+ end
28
+
29
+ def common_payload(severity, timestamp, tags)
30
+ {
31
+ tags: [@config.default_tag, tags].join(' ').strip,
32
+ app: @config.app,
33
+ app_env: @config.app_env,
34
+ instance: @config.instance,
35
+ created_at: timestamp.iso8601(3),
36
+ ok: !%w[FATAL ERROR].include?(severity)
37
+ }
38
+ end
39
+
40
+ def msg_payload(msg)
41
+ case msg
42
+ when ::Exception
43
+ error_payload(msg)
44
+ when Hash
45
+ hash_payload(msg)
46
+ else
47
+ { details: { message: try_to_json(msg) } }
48
+ end
49
+ end
50
+
51
+ def error_payload(e)
52
+ error_hash = {
53
+ class: e.class,
54
+ message: e.message
55
+ }
56
+ error_hash.merge!(backtrace: "\n" + e.backtrace.join("\n") + "\n") if e.backtrace
57
+ payload = {
58
+ error: error_hash,
59
+ ok: false
60
+ }
61
+ payload.merge!(details: e.details) if e.respond_to?(:details)
62
+ payload
63
+ end
64
+
65
+ def hash_payload(msg)
66
+ details = msg.delete(:details)
67
+ payload = { details: msg }
68
+ deep_merge!(payload, { details: details }) unless details.nil?
69
+ payload
70
+ end
71
+
72
+ def try_to_json(str)
73
+ ::JSON.parse(str)
74
+ rescue ::JSON::ParserError
75
+ str
76
+ end
77
+
78
+ def deep_merge!(hash, other_hash)
79
+ hash.merge!(other_hash) do |_, this_val, other_val|
80
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
81
+ deep_merge!(this_val, other_val)
82
+ else
83
+ other_val
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'logger'
4
+ require 'forwardable'
5
+ require 'luna_park/extensions/severity_levels'
6
+ require 'luna_park/notifiers/tagged_log/options'
7
+ require 'luna_park/notifiers/tagged_log/tagged_formatter'
8
+
9
+ module LunaPark
10
+ module Notifiers
11
+ module TaggedLog
12
+ include Extensions::SeverityLevels
13
+ extend Forwardable
14
+
15
+ SEVERITY_LEVELS = {
16
+ unknown: Logger::Severity::UNKNOWN,
17
+ fatal: Logger::Severity::FATAL,
18
+ error: Logger::Severity::ERROR,
19
+ warning: Logger::Severity::WARN,
20
+ info: Logger::Severity::INFO,
21
+ debug: Logger::Severity::DEBUG
22
+ }.freeze
23
+
24
+ private_constant :SEVERITY_LEVELS
25
+
26
+ def_delegators :formatter, :push_tags, :clear_tags!
27
+ attr_accessor :output
28
+
29
+ module Formatter
30
+ def call(severity, timestamp, progname, msg)
31
+ super(severity, timestamp, progname, msg, tags_text)
32
+ end
33
+
34
+ def tagged(*tags)
35
+ new_tags = push_tags(*tags)
36
+ yield self
37
+ ensure
38
+ pop_tags(new_tags.size)
39
+ end
40
+
41
+ def push_tags(*tags)
42
+ tags.flatten!
43
+ tags.reject! { |t| t.respond_to?(:empty?) ? !!t.empty? : !t }
44
+ current_tags.concat tags
45
+ tags
46
+ end
47
+
48
+ def pop_tags(size = 1)
49
+ current_tags.pop(size)
50
+ end
51
+
52
+ def clear_tags!
53
+ current_tags.clear
54
+ end
55
+
56
+ def current_tags
57
+ thread_key = @thread_key ||= "tagged_log_tag_store_tags:#{object_id}"
58
+ Thread.current[thread_key] ||= []
59
+ end
60
+
61
+ def tags_text
62
+ current_tags.join(' ').strip
63
+ end
64
+ end
65
+
66
+ def tagged(*tags)
67
+ if block_given?
68
+ formatter.tagged(*tags) { yield self }
69
+ else
70
+ logger = LunaPark::Notifiers::TaggedLog.new(
71
+ output, **formatter.config.to_h
72
+ )
73
+ logger.push_tags(*formatter.current_tags, *tags)
74
+ logger
75
+ end
76
+ end
77
+
78
+ def post(msg, lvl: :error, **details)
79
+ severity = severity(lvl)
80
+ message = { original_msg: msg, details: details }
81
+ add severity, message
82
+ end
83
+
84
+ def severity(lvl)
85
+ severity = SEVERITY_LEVELS[lvl]
86
+ raise ArgumentError, "Unknown level #{lvl}" if severity.nil?
87
+
88
+ severity
89
+ end
90
+
91
+ def self.new(output = $stdout, **options)
92
+ config = LunaPark::Notifiers::TaggedLog::Options.wrap(options)
93
+
94
+ logger = Logger.new(output)
95
+ logger.formatter = LunaPark::Notifiers::TaggedLog::TaggedFormatter.new
96
+ logger.formatter.config = config
97
+ logger.formatter.extend(Formatter)
98
+ logger.extend(self)
99
+ logger.output = output
100
+ logger.min_lvl = config.min_lvl
101
+ logger
102
+ end
103
+ end
104
+ end
105
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LunaPark
4
- VERSION = '0.11.6'
4
+ VERSION = '0.12.0'
5
5
  end
data/luna_park.gemspec CHANGED
@@ -39,6 +39,10 @@ Gem::Specification.new do |spec|
39
39
  spec.add_development_dependency 'byebug', '~> 11.1'
40
40
  spec.add_development_dependency 'codecov', '~> 0.2'
41
41
  spec.add_development_dependency 'dry-validation', '~> 1.1'
42
+ spec.add_development_dependency 'guard'
43
+ spec.add_development_dependency 'guard-bundler'
44
+ spec.add_development_dependency 'guard-rspec'
45
+ spec.add_development_dependency 'guard-rubocop'
42
46
  spec.add_development_dependency 'i18n', '~> 1.8'
43
47
  spec.add_development_dependency 'overcommit', '~> 0.55'
44
48
  spec.add_development_dependency 'pry', '~> 0.13'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: luna_park
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.6
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Kudrin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-10-06 00:00:00.000000000 Z
12
+ date: 2023-02-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bugsnag
@@ -81,6 +81,62 @@ dependencies:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
83
  version: '1.1'
84
+ - !ruby/object:Gem::Dependency
85
+ name: guard
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: guard-bundler
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: guard-rspec
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: guard-rubocop
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
84
140
  - !ruby/object:Gem::Dependency
85
141
  name: i18n
86
142
  requirement: !ruby/object:Gem::Requirement
@@ -270,7 +326,6 @@ executables: []
270
326
  extensions: []
271
327
  extra_rdoc_files: []
272
328
  files:
273
- - ".github/gem-push.yml"
274
329
  - ".github/workflows/gem-push.yml"
275
330
  - ".gitignore"
276
331
  - ".overcommit.yml"
@@ -282,6 +337,7 @@ files:
282
337
  - CHANGELOG.md
283
338
  - Gemfile
284
339
  - Gemfile.lock
340
+ - Guardfile
285
341
  - LICENSE
286
342
  - LICENSE.txt
287
343
  - README.md
@@ -375,7 +431,11 @@ files:
375
431
  - lib/luna_park/mappers/simple.rb
376
432
  - lib/luna_park/notifiers/bugsnag.rb
377
433
  - lib/luna_park/notifiers/log.rb
434
+ - lib/luna_park/notifiers/log/formatters.rb
378
435
  - lib/luna_park/notifiers/sentry.rb
436
+ - lib/luna_park/notifiers/tagged_log.rb
437
+ - lib/luna_park/notifiers/tagged_log/options.rb
438
+ - lib/luna_park/notifiers/tagged_log/tagged_formatter.rb
379
439
  - lib/luna_park/repositories/postgres.rb
380
440
  - lib/luna_park/repositories/sequel.rb
381
441
  - lib/luna_park/repository.rb
data/.github/gem-push.yml DELETED
@@ -1,43 +0,0 @@
1
- name: Ruby Gem
2
-
3
- on:
4
- push:
5
- branches: [ master ]
6
-
7
- jobs:
8
- build:
9
- name: Build + Publish
10
- runs-on: ubuntu-latest
11
- permissions:
12
- contents: read
13
- packages: write
14
-
15
- steps:
16
- - uses: actions/checkout@v2
17
- - name: Set up Ruby 2.6
18
- uses: actions/setup-ruby@v1
19
- with:
20
- ruby-version: 2.5.x
21
-
22
- - name: Publish to GPR
23
- run: |
24
- mkdir -p $HOME/.gem
25
- touch $HOME/.gem/credentials
26
- chmod 0600 $HOME/.gem/credentials
27
- printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
28
- gem build *.gemspec
29
- gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
30
- env:
31
- GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
32
- OWNER: ${{ github.repository_owner }}
33
-
34
- - name: Publish to RubyGems
35
- run: |
36
- mkdir -p $HOME/.gem
37
- touch $HOME/.gem/credentials
38
- chmod 0600 $HOME/.gem/credentials
39
- printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
40
- gem build *.gemspec
41
- gem push *.gem
42
- env:
43
- GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"