eco-helpers 3.0.20 → 3.0.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -3
- data/lib/eco/api/common/loaders/config/cli.rb +9 -0
- data/lib/eco/api/common/loaders/config.rb +1 -0
- data/lib/eco/api/common/people/default_parsers/xls_parser.rb +1 -1
- data/lib/eco/api/common/session/logger/cache.rb +10 -4
- data/lib/eco/api/common/session/logger/channels.rb +41 -0
- data/lib/eco/api/common/session/logger.rb +9 -0
- data/lib/eco/api/session/batch/job.rb +11 -0
- data/lib/eco/cli_default/input.rb +49 -29
- data/lib/eco/cli_default/options.rb +4 -1
- data/lib/eco/cli_default/people.rb +102 -47
- data/lib/eco/cli_default/people_filters.rb +4 -1
- data/lib/eco/language/auxiliar_logger.rb +16 -3
- data/lib/eco/language/basic_logger.rb +1 -0
- data/lib/eco/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7764e6e3e78228f59b9a5f5baf2aa8602c627882905a23270007b4fe1a09c9f
|
4
|
+
data.tar.gz: aca94b571b1c70c000e0d88f09182f2339a306187c5f9651968e9692981d79d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bcef313643bc67ba9d90755e3ce8a3a3a39c1973404b2dcd35292b76c67d158ad3e9c666414e2f6254776eeb800f4d07fc2ab10953a15e9e2b293d2b8f15303e
|
7
|
+
data.tar.gz: 3d12155562df35e9ecadea021a758f922f35ab68d689592e4a319e41232b4865a87e22c0e333b1083e42340418f57388f24139748246d08652142ef52f1a041d
|
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,27 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
-
## [3.0.
|
5
|
+
## [3.0.21] - 2024-12-16
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- `Eco::API::Common::Session::Logger`
|
10
|
+
- Implement **channels** logging.
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
|
14
|
+
- Moved `input` and `people` **cli_default configurations** to a class definition
|
15
|
+
- `Eco::Language::AuxiliarLogger#log`
|
16
|
+
- Allow for multiple levels
|
17
|
+
- Return `NilClass`
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
|
21
|
+
- `Eco::API::Session::Batch::Job#summary`
|
22
|
+
- Ensure a summary of pending jobs can be handled, even if `#launch` was NOT explicitly called.
|
23
|
+
- As we don't consolidate, it may give more actual updates than pending, yet this is better than providing the `count` of entries in the job's queue.
|
24
|
+
|
25
|
+
## [3.0.20] - 2024-12-07
|
6
26
|
|
7
27
|
### Added
|
8
28
|
|
@@ -16,8 +36,6 @@ All notable changes to this project will be documented in this file.
|
|
16
36
|
|
17
37
|
- On failure, `Eco::API::Session::Job#summary` to give precise estimates on what is pending to be run.
|
18
38
|
|
19
|
-
### Fixed
|
20
|
-
|
21
39
|
## [3.0.19] - 2024-11-21
|
22
40
|
|
23
41
|
### Added
|
@@ -27,7 +27,7 @@ class Eco::API::Common::People::DefaultParsers::XLSParser < Eco::API::Common::Lo
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def expected_headers
|
30
|
-
log(:
|
30
|
+
log(:info) {
|
31
31
|
"Headers detection is using your fields_map.json file (native behaviour)"
|
32
32
|
}
|
33
33
|
session.fields_mapper.list(:external).uniq
|
@@ -4,7 +4,8 @@ module Eco
|
|
4
4
|
module Session
|
5
5
|
class Logger
|
6
6
|
class Cache
|
7
|
-
LEVELS
|
7
|
+
LEVELS = %w[UNKNOWN FATAL ERROR WARN INFO DEBUG].freeze
|
8
|
+
CHANNELS = Logger::CHANNELS.map(&:to_s).map(&:upcase).freeze
|
8
9
|
|
9
10
|
def initialize
|
10
11
|
reset
|
@@ -56,7 +57,8 @@ module Eco
|
|
56
57
|
end
|
57
58
|
|
58
59
|
def to_datetime(value)
|
59
|
-
return
|
60
|
+
return unless value
|
61
|
+
|
60
62
|
Time.parse(value)
|
61
63
|
end
|
62
64
|
|
@@ -64,7 +66,7 @@ module Eco
|
|
64
66
|
levels = [value].flatten.map {|v| to_level(v)}.compact
|
65
67
|
return levels unless levels.empty?
|
66
68
|
|
67
|
-
|
69
|
+
valid_levels
|
68
70
|
end
|
69
71
|
|
70
72
|
def to_level(value)
|
@@ -75,7 +77,7 @@ module Eco
|
|
75
77
|
|
76
78
|
def valid_level!(str)
|
77
79
|
return true unless str
|
78
|
-
return true if
|
80
|
+
return true if valid_levels.any? {|lev| str == lev}
|
79
81
|
|
80
82
|
msg = "Unknown level #{str}. Should be one of #{LEVELS}"
|
81
83
|
raise ArgumentError, msg
|
@@ -87,6 +89,10 @@ module Eco
|
|
87
89
|
|
88
90
|
value
|
89
91
|
end
|
92
|
+
|
93
|
+
def valid_levels
|
94
|
+
@valid_levels ||= self.class::LEVELS | self.class::CHANNELS
|
95
|
+
end
|
90
96
|
end
|
91
97
|
end
|
92
98
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Eco
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module Session
|
5
|
+
class Logger
|
6
|
+
module Channels
|
7
|
+
CHANNELS = %i[general].freeze
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def included(base)
|
11
|
+
super
|
12
|
+
base.extend ClassMethods
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def channels!(&def_block)
|
18
|
+
str = "Block with channel implementation expected. None given."
|
19
|
+
raise ArgumentError, str unless block_given?
|
20
|
+
|
21
|
+
channels.each do |channel|
|
22
|
+
meth = channel.to_s.downcase.to_sym
|
23
|
+
|
24
|
+
define_method(meth) do |msg = nil, &block|
|
25
|
+
def_block.call(meth, msg, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def channels
|
33
|
+
self::CHANNELS
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -5,6 +5,15 @@ module Eco
|
|
5
5
|
class Logger < Eco::Language::BasicLogger
|
6
6
|
TIMESTAMP_PATTERN = '%Y-%m-%dT%H:%M:%S'.freeze
|
7
7
|
|
8
|
+
require_relative 'logger/channels'
|
9
|
+
include Channels
|
10
|
+
|
11
|
+
channels! do |channel, message = nil, &block|
|
12
|
+
format_proc(console: true) do |severity, datetime, msg, formatted_msg|
|
13
|
+
cache.add(severity, datetime, msg, formatted_msg)
|
14
|
+
end.call(channel, Time.now, 'prog_name', message || block.call)
|
15
|
+
end
|
16
|
+
|
8
17
|
attr_reader :cache
|
9
18
|
|
10
19
|
def initialize(file_level: ::Logger::DEBUG, log_file: nil, enviro: nil, **kargs)
|
@@ -146,6 +146,16 @@ module Eco
|
|
146
146
|
@pending
|
147
147
|
end
|
148
148
|
|
149
|
+
# @note some times we need a summary of what actually
|
150
|
+
# is going to be run without invoking `launch`
|
151
|
+
# (i.e. when there's a uncompliance with the batch policy)
|
152
|
+
def ensure_requests!
|
153
|
+
return if instance_variable_defined?(:@requests)
|
154
|
+
|
155
|
+
pqueue = processed_queue
|
156
|
+
@requests = as_update(pqueue)
|
157
|
+
end
|
158
|
+
|
149
159
|
# @note it requires launch to be firstly invoked
|
150
160
|
# @raise [Exception] if 'launch' has not firstly invoked
|
151
161
|
# @return [Enumbrable<Hash>] the last requests that the queue will generate
|
@@ -250,6 +260,7 @@ module Eco
|
|
250
260
|
def summary
|
251
261
|
[].tap do |msg|
|
252
262
|
msg << "PENDING Job -------->\n" if pending?
|
263
|
+
ensure_requests!
|
253
264
|
msg << feedback.generate(requests, only_stats: true)
|
254
265
|
|
255
266
|
if batch_policy && !batch_policy.compliant?(request_stats)
|
@@ -1,6 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
formats = {
|
1
|
+
class Eco::CliDefault::Input < Eco::API::Common::Loaders::CliConfig
|
2
|
+
FORMATS = {
|
4
3
|
csv: {
|
5
4
|
option: ["-csv"],
|
6
5
|
extname: [".csv", ".txt"]
|
@@ -17,51 +16,74 @@ ASSETS.cli.config do |cnf|
|
|
17
16
|
option: ["-json"],
|
18
17
|
extname: [".json"]
|
19
18
|
}
|
20
|
-
}
|
19
|
+
}.freeze
|
21
20
|
|
22
|
-
|
23
|
-
|
21
|
+
class << self
|
22
|
+
attr_reader :options, :session
|
24
23
|
|
24
|
+
def encoding
|
25
|
+
options.dig(:input, :file, :encoding)
|
26
|
+
end
|
27
|
+
|
28
|
+
def format_by_cli
|
29
|
+
FORMATS.reduce(nil) do |matched, (frm, selectors)|
|
30
|
+
next matched if matched
|
31
|
+
|
32
|
+
used = selectors[:option].reduce(false) do |us, option|
|
33
|
+
SCR.get_arg(option) || us
|
34
|
+
end
|
35
|
+
|
36
|
+
next frm if used
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def format_by_ext(ext)
|
41
|
+
FORMATS.reduce(nil) do |matched, (frm, selectors)|
|
42
|
+
next matched if matched
|
43
|
+
next frm if selectors[:extname].any? {|e| ext == e}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
input(default_option: "-entries-from") do |session, str_opt, options|
|
49
|
+
@options = options
|
50
|
+
@session = session
|
51
|
+
input = []
|
25
52
|
next input unless SCR.get_arg(str_opt)
|
26
53
|
|
27
54
|
file = SCR.get_file(str_opt, required: true)
|
28
55
|
|
29
56
|
# Command line check
|
30
|
-
format =
|
31
|
-
used = selectors[:option].reduce(false) {|us, option| SCR.get_arg(option) || us}
|
32
|
-
next matched if matched
|
33
|
-
next frm if used
|
34
|
-
end
|
57
|
+
format = format_by_cli
|
35
58
|
|
36
59
|
# File/Folder check
|
37
60
|
file = File.expand_path(file)
|
61
|
+
|
38
62
|
if File.directory?(file)
|
39
63
|
folder = file
|
40
64
|
file = Dir.glob("#{file}/*").reject {|f| File.directory?(f)}
|
41
|
-
ext = (format
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
65
|
+
ext = FORMATS.dig(format, :extname)
|
66
|
+
ext ||= [File.extname(file.first)]
|
67
|
+
file = file.select do |f|
|
68
|
+
ext.any? {|e| File.extname(f) == e}
|
69
|
+
end.tap do |files|
|
70
|
+
next unless files.empty?
|
71
|
+
|
72
|
+
session.log(:error) {
|
73
|
+
"Could not find any file with extension: #{ext} in folder '#{folder}'"
|
74
|
+
}
|
75
|
+
exit(1)
|
49
76
|
end
|
50
77
|
else
|
51
|
-
ext = File.extname(file)
|
78
|
+
ext = [File.extname(file)]
|
52
79
|
end
|
53
80
|
|
54
|
-
format ||=
|
55
|
-
next matched if matched
|
56
|
-
next frm if selectors[:extname].any? {|e| ext == e}
|
57
|
-
end
|
81
|
+
format ||= format_by_ext(ext.first)
|
58
82
|
format ||= :csv
|
59
83
|
|
60
|
-
options.deep_merge!(input: {file: {name:
|
84
|
+
options.deep_merge!(input: {file: {name: file}})
|
61
85
|
options.deep_merge!(input: {file: {format: format}})
|
62
86
|
|
63
|
-
encoding = options.dig(:input, :file, :encoding)
|
64
|
-
|
65
87
|
case format
|
66
88
|
when :xml
|
67
89
|
[file].flatten.each {|f| session.config.files.validate(:xml, f)}
|
@@ -83,5 +105,3 @@ ASSETS.cli.config do |cnf|
|
|
83
105
|
input
|
84
106
|
end
|
85
107
|
end
|
86
|
-
|
87
|
-
# rubocop:enable Metrics/BlockLength
|
@@ -69,7 +69,10 @@ ASSETS.cli.config do |cnf| # rubocop:disable Metrics/BlockLength
|
|
69
69
|
sch_id = session.schemas.to_id(sch_name)
|
70
70
|
|
71
71
|
unless sch_id
|
72
|
-
msg = "You need to specify a correct schema id or name.
|
72
|
+
msg = "You need to specify a correct schema id or name. "
|
73
|
+
msg << "'#{sch_name}' does not exist. Correct options are: "
|
74
|
+
msg << session.schemas.map(&:name).join(", ")
|
75
|
+
|
73
76
|
session.log(:error) { msg }
|
74
77
|
exit(1)
|
75
78
|
end
|
@@ -1,69 +1,124 @@
|
|
1
|
-
|
1
|
+
class Eco::CliDefault::People < Eco::API::Common::Loaders::CliConfig
|
2
|
+
MAX_GET_PARTIAL = 12_000
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
get = {} if get.nil?
|
4
|
+
class << self
|
5
|
+
attr_reader :options, :session
|
6
|
+
attr_writer :get_full, :get_partial
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
def get_options # rubocop:disable Naming/AccessorMethodName
|
9
|
+
get = options.dig(:people, :get)
|
10
|
+
get = {} if get.nil?
|
11
|
+
get
|
12
|
+
end
|
13
|
+
|
14
|
+
def no_get?
|
15
|
+
get_options == false
|
16
|
+
end
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
18
|
+
def from_remote?
|
19
|
+
return false unless get_options
|
20
|
+
|
21
|
+
get_options[:from] == :remote
|
22
|
+
end
|
23
|
+
|
24
|
+
def from_local?
|
25
|
+
return false unless get_options
|
26
|
+
|
27
|
+
get_options[:from] == :local
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_full?
|
31
|
+
return @get_full if instance_variable_defined?(:@get_full)
|
32
|
+
return false unless from_remote?
|
33
|
+
|
34
|
+
get_options[:type] == :full
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_partial?
|
38
|
+
return @get_partial if instance_variable_defined?(:@get_partial)
|
39
|
+
return false unless from_remote?
|
40
|
+
|
41
|
+
@get_partial = (get_options[:type] == :partial)
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_by_file?
|
45
|
+
return false unless from_local?
|
46
|
+
|
47
|
+
get_options[:type] == :file
|
48
|
+
end
|
49
|
+
|
50
|
+
def source_file
|
51
|
+
return unless get_by_file?
|
52
|
+
|
53
|
+
get_options[:file]
|
54
|
+
end
|
55
|
+
|
56
|
+
def switch_to_full_remote!
|
57
|
+
self.get_full = true
|
58
|
+
self.get_partial = false
|
59
|
+
|
60
|
+
options.deep_merge!(people: {
|
61
|
+
get: {
|
62
|
+
from: :remote,
|
63
|
+
type: :full
|
64
|
+
}
|
65
|
+
})
|
66
|
+
end
|
67
|
+
|
68
|
+
def switch_to_full_local!
|
69
|
+
self.get_full = true
|
70
|
+
self.get_partial = false
|
71
|
+
|
72
|
+
options.deep_merge!(people: {
|
73
|
+
get: {
|
74
|
+
from: :local,
|
75
|
+
type: :full
|
76
|
+
}
|
77
|
+
})
|
78
|
+
end
|
79
|
+
|
80
|
+
def optimize_get_partial!(input)
|
81
|
+
return unless get_partial?
|
14
82
|
|
15
|
-
# -get-partial: validate input present and under max
|
16
|
-
if get_partial
|
17
83
|
msg = "To use -get-partial (partial updates), you need to use -entries-from"
|
18
84
|
raise msg unless input.is_a?(Enumerable)
|
19
85
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
options.deep_merge!(people: {
|
31
|
-
get: {
|
32
|
-
from: :remote,
|
33
|
-
type: :full
|
34
|
-
}
|
35
|
-
})
|
36
|
-
end
|
86
|
+
return unless input.count > MAX_GET_PARTIAL
|
87
|
+
|
88
|
+
msg = "(Optimization) "
|
89
|
+
msg << "Switching from partial to full people download. "
|
90
|
+
msg << "Input (#{input.count}) surpases MAX_GET_PARTIAL "
|
91
|
+
msg << "(#{MAX_GET_PARTIAL}) entries."
|
92
|
+
session.log(:info) { msg }
|
93
|
+
|
94
|
+
switch_to_full_remote!
|
37
95
|
end
|
96
|
+
end
|
97
|
+
|
98
|
+
people do |input, session, options|
|
99
|
+
@options = options
|
100
|
+
@session = session
|
38
101
|
|
39
|
-
|
102
|
+
# -get-partial: validate input present and under max
|
103
|
+
optimize_get_partial!(input) if get_partial?
|
104
|
+
|
105
|
+
if no_get?
|
40
106
|
Eco::API::Organization::People.new([])
|
41
|
-
elsif get_full
|
107
|
+
elsif get_full?
|
42
108
|
# -get-people
|
43
109
|
session.micro.people_cache
|
44
|
-
elsif get_partial
|
110
|
+
elsif get_partial?
|
45
111
|
# -get-partial
|
46
112
|
session.micro.people_search(input, options: options)
|
47
|
-
elsif get_by_file
|
113
|
+
elsif get_by_file?
|
48
114
|
# -people-from-backup
|
49
|
-
session.micro.people_load(
|
115
|
+
session.micro.people_load(source_file, modifier: :file)
|
50
116
|
else
|
51
|
-
|
52
|
-
get: {
|
53
|
-
from: :local,
|
54
|
-
type: :full
|
55
|
-
}
|
56
|
-
})
|
57
|
-
|
117
|
+
switch_to_full_local!
|
58
118
|
people = session.micro.people_load(modifier: %i[newest save])
|
59
119
|
|
60
120
|
if people.empty?
|
61
|
-
|
62
|
-
get: {
|
63
|
-
from: :remote,
|
64
|
-
type: :full
|
65
|
-
}
|
66
|
-
})
|
121
|
+
switch_to_full_remote!
|
67
122
|
people = session.micro.people_cache
|
68
123
|
end
|
69
124
|
|
@@ -92,7 +92,10 @@ ASSETS.cli.config do |cnf| # rubocop:disable Metrics/BlockLength
|
|
92
92
|
sch_id = session.schemas.to_id(sch_name)
|
93
93
|
|
94
94
|
unless sch_id
|
95
|
-
msg = "You need to specify a correct schema id or name.
|
95
|
+
msg = "You need to specify a correct schema id or name. "
|
96
|
+
msg << "'#{sch_name}' does not exist. Correct options are: "
|
97
|
+
msg << session.schemas.map(&:name).join(", ")
|
98
|
+
|
96
99
|
session.log(:error) { msg }
|
97
100
|
exit(1)
|
98
101
|
end
|
@@ -21,10 +21,23 @@ module Eco
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# Shortcut to logger.
|
24
|
-
|
25
|
-
|
24
|
+
# @todo allow for more channels (atm it's just :general )
|
25
|
+
# @note when `:general` is included, it ensures at least
|
26
|
+
# `:info` level is also logged.
|
27
|
+
# @return [NilClass]
|
28
|
+
def log(*levels, &block)
|
29
|
+
return unless logger
|
26
30
|
|
27
|
-
|
31
|
+
levels = levels.compact.uniq.map(&:to_sym)
|
32
|
+
levels.unshift(:info) if levels.include?(:general) && levels.length == 1
|
33
|
+
|
34
|
+
levels.each do |level|
|
35
|
+
next unless logger.respond_to?(:level)
|
36
|
+
|
37
|
+
logger.send(level, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
nil
|
28
41
|
end
|
29
42
|
end
|
30
43
|
end
|
@@ -67,6 +67,7 @@ module Eco
|
|
67
67
|
def format_proc(console: true, &block)
|
68
68
|
proc do |severity, datetime, _progname, msg|
|
69
69
|
str_stamp = console ? console_timestamp(datetime) : timestamp(datetime)
|
70
|
+
|
70
71
|
"#{severity.to_s[0]}: #{str_stamp}#{msg}\n".tap do |formatted_msg|
|
71
72
|
block&.call(severity, datetime, msg, formatted_msg)
|
72
73
|
end
|
data/lib/eco/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eco-helpers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oscar Segura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -538,6 +538,7 @@ files:
|
|
538
538
|
- lib/eco/api/common/loaders/base.rb
|
539
539
|
- lib/eco/api/common/loaders/case_base.rb
|
540
540
|
- lib/eco/api/common/loaders/config.rb
|
541
|
+
- lib/eco/api/common/loaders/config/cli.rb
|
541
542
|
- lib/eco/api/common/loaders/config/session.rb
|
542
543
|
- lib/eco/api/common/loaders/config/workflow.rb
|
543
544
|
- lib/eco/api/common/loaders/config/workflow/mailer.rb
|
@@ -580,6 +581,7 @@ files:
|
|
580
581
|
- lib/eco/api/common/session/helpers/prompt_user.rb
|
581
582
|
- lib/eco/api/common/session/logger.rb
|
582
583
|
- lib/eco/api/common/session/logger/cache.rb
|
584
|
+
- lib/eco/api/common/session/logger/channels.rb
|
583
585
|
- lib/eco/api/common/session/logger/log.rb
|
584
586
|
- lib/eco/api/common/session/mailer.rb
|
585
587
|
- lib/eco/api/common/session/mailer/aws_provider.rb
|