sinlog 0.0.4 → 0.0.6

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.
@@ -1,62 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Sinlog
4
- # LogExt is a Refinement that adds convenient logging methods to all objects.
5
- #
6
- # When activated with `using Sinlog::LogExt`, any object can call:
7
- #
3
+ module Sinlog
8
4
  # == Overview
9
5
  #
10
- # * `log_dbg` – Logs the object at DEBUG level
11
- # * `log_info` – Logs the object at INFO level
12
- # * `log_warn` – Logs the object at WARN level
13
- # * `log_err` – Logs the object at ERROR level
14
- # * `log_fatal` – Logs the object at FATAL level
15
- # * `log_unk` – Logs the object at UNKNOWN level
16
- #
17
- # == Example
18
- #
19
- # require 'sinlog'
20
- #
21
- # class A
22
- # using Sinlog::LogExt
23
- # def demo
24
- # "Something happened".log_warn
25
- # end
26
- # end
6
+ # * `log_dbg` – DEBUG
7
+ # * `log_info` – INFO
8
+ # * `log_warn` – WARN
9
+ # * `log_err` – ERROR
10
+ # * `log_fatal` – FATAL
11
+ # * `log_unk` – UNKNOWN
27
12
  #
28
13
  module LogExt
29
- refine Object do
30
- # Logs the current object at *debug* level using Sinlog.logger
31
- def log_dbg
32
- Sinlog.logger.debug(self)
33
- end
14
+ # Logs the current object at *debug* level using Sinlog.logger
15
+ def log_dbg
16
+ Sinlog.logger.debug(self)
17
+ end
34
18
 
35
- # Logs the current object at *information* level using Sinlog.logger
36
- def log_info
37
- Sinlog.logger.info(self)
38
- end
19
+ # Logs the current object at *information* level using Sinlog.logger
20
+ def log_info
21
+ Sinlog.logger.info(self)
22
+ end
39
23
 
40
- # Logs the current object at *warning* level using Sinlog.logger
41
- def log_warn
42
- Sinlog.logger.warn(self)
43
- end
24
+ # Logs the current object at *warning* level using Sinlog.logger
25
+ def log_warn
26
+ Sinlog.logger.warn(self)
27
+ end
44
28
 
45
- # Logs the current object at *error* level using Sinlog.logger
46
- def log_err
47
- Sinlog.logger.error(self)
48
- end
29
+ # Logs the current object at *error* level using Sinlog.logger
30
+ def log_err
31
+ Sinlog.logger.error(self)
32
+ end
49
33
 
50
- # Logs the current object at *fatal* level using Sinlog.logger
51
- def log_fatal
52
- Sinlog.logger.fatal(self)
53
- end
34
+ # Logs the current object at *fatal* level using Sinlog.logger
35
+ def log_fatal
36
+ Sinlog.logger.fatal(self)
37
+ end
54
38
 
55
- # Logs the current object at *unknown* level using Sinlog.logger
56
- def log_unk
57
- Sinlog.logger.unknown(self)
58
- end
59
- # -----
39
+ # Logs the current object at *unknown* level using Sinlog.logger
40
+ def log_unk
41
+ Sinlog.logger.unknown(self)
60
42
  end
61
43
  end
44
+ # -----
45
+ private_constant :LogExt
62
46
  end
@@ -1,57 +1,153 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Sinlog
3
+ module Sinlog
4
4
  # Provides logging helpers for any object.
5
5
  #
6
6
  # == Overview
7
7
  #
8
- # * `log_dbg` – Logs the object at DEBUG level
9
- # * `log_info` – Logs the object at INFO level
10
- # * `log_warn` – Logs the object at WARN level
11
- # * `log_err` – Logs the object at ERROR level
12
- # * `log_fatal` – Logs the object at FATAL level
13
- # * `log_unk` – Logs the object at UNKNOWN level
8
+ # * `log_dbg` – DEBUG
9
+ # * `log_info` – INFO
10
+ # * `log_warn` – WARN
11
+ # * `log_err` – ERROR
12
+ # * `log_fatal` – FATAL
13
+ # * `log_unk` – UNKNOWN
14
14
  #
15
15
  # == Example
16
16
  #
17
17
  # require 'sinlog'
18
18
  #
19
- # include Sinlog::Loggleable
19
+ # include Sinlog::Mixin
20
20
  #
21
21
  # "A debug message".log_dbg
22
22
  # "Hello, world".log_info
23
23
  #
24
- module Loggleable
25
- # Logs the current object at *debug* level using Sinlog.logger
26
- def log_dbg
27
- Sinlog.logger.debug(self)
28
- end
29
-
30
- # Logs the current object at *information* level using Sinlog.logger
31
- # logger.info
32
- def log_info
33
- Sinlog.logger.info(self)
34
- end
35
-
36
- # Logs the current object at *warning* level using Sinlog.logger
37
- def log_warn
38
- Sinlog.logger.warn(self)
24
+ # Object.method_defined?(:log_warn) #=> true
25
+ #
26
+ module Mixin
27
+ def self.included(_host)
28
+ ::Object.include(LogExt)
39
29
  end
30
+ end
40
31
 
41
- # Logs the current object at *error* level using Sinlog.logger
42
- def log_err
43
- Sinlog.logger.error(self)
32
+ # Provides logging helpers for any object.
33
+ #
34
+ # - The main difference from `Sinlog::Mixin` is that `Refin` uses Refinements instead of Mixins.
35
+ # - You need to activate it with `using Sinlog::Refin`
36
+ # - rather than `include Sinlog::Mixin`.
37
+ #
38
+ # == Source
39
+ #
40
+ # refine ::Object { import_methods LogExt }
41
+ #
42
+ # == Overview
43
+ #
44
+ # * `log_dbg` – DEBUG
45
+ # * `log_info` – INFO
46
+ # * `log_warn` – WARN
47
+ # * `log_err` – ERROR
48
+ # * `log_fatal` – FATAL
49
+ # * `log_unk` – UNKNOWN
50
+ #
51
+ # == Example
52
+ #
53
+ # require 'sinlog'
54
+ #
55
+ # module A
56
+ # module_function
57
+ # using Sinlog::Refin
58
+ #
59
+ # def demo = "Something happened".log_warn
60
+ # def respon_to_log_dbg? = [].respond_to? :log_dbg
61
+ # end
62
+ #
63
+ # A.demo
64
+ # # => [WARN] 11:17:38.024 Something happened
65
+ # # => (WARN is displayed in yellow highlight; 11:17:38.024 is the current time and may vary)
66
+ #
67
+ # A.respon_to_log_dbg? # => true
68
+ # [].respond_to? :log_dbg #=> false
69
+ #
70
+ module Refin
71
+ refine ::Object do
72
+ import_methods LogExt
44
73
  end
74
+ end
45
75
 
46
- # Logs the current object at *fatal* level using Sinlog.logger
47
- def log_fatal
48
- Sinlog.logger.fatal(self)
76
+ # Provids convenient logging methods.
77
+ #
78
+ # Similar to `Sinlog::Refin`, but methods omit the `log_` prefix.
79
+ #
80
+ # For example:
81
+ # * `"msg".err` instead of `"msg".log_err`;
82
+ # * `"msg".warn` instead of `"msg".log_warn`
83
+ #
84
+ # == Source
85
+ #
86
+ # refine ::Object { import_methods LogShortExt }
87
+ #
88
+ # == Overview
89
+ #
90
+ # * `dbg` – DEBUG
91
+ # * `info` – INFO
92
+ # * `warn` – WARN
93
+ # * `err` – ERROR
94
+ # * `fatal` – FATAL
95
+ # * `unk` – UNKNOWN
96
+ #
97
+ # == Example
98
+ #
99
+ # require 'sinlog'
100
+ #
101
+ # module A
102
+ # module_function
103
+ # using Sinlog::ShortRefin
104
+ #
105
+ # def demo = "Something happened".warn
106
+ # def respon_to_dbg? = [].respond_to? :dbg
107
+ # end
108
+ #
109
+ # A.demo
110
+ # # => [WARN] 11:17:38.024 Something happened
111
+ # # => (WARN is displayed in yellow highlight; 11:17:38.024 is the current time and may vary)
112
+ #
113
+ # A.respon_to_dbg? # => true
114
+ # [].respond_to? :dbg #=> false
115
+ #
116
+ module ShortRefin
117
+ refine ::Object do
118
+ import_methods LogShortExt
49
119
  end
120
+ end
50
121
 
51
- # Logs the current object at *unknown* level using Sinlog.logger
52
- def log_unk
53
- Sinlog.logger.unknown(self)
122
+ # Provids convenient logging methods.
123
+ #
124
+ # Similar to `Sinlog::Mixin`, but methods omit the `log_` prefix.
125
+ #
126
+ # Note: Since mixin monkey patching pollutes the global scope, use `include Sinlog::ShortMixin` with caution.
127
+ #
128
+ # == Overview
129
+ #
130
+ # * `dbg` – DEBUG
131
+ # * `info` – INFO
132
+ # * `warn` – WARN
133
+ # * `err` – ERROR
134
+ # * `fatal` – FATAL
135
+ # * `unk` – UNKNOWN
136
+ #
137
+ # == Example
138
+ #
139
+ # require 'sinlog'
140
+ #
141
+ # include Sinlog::ShortMixin
142
+ #
143
+ # "A debug message".dbg
144
+ # "Hello, world".info
145
+ #
146
+ # Object.method_defined?(:err) #=> true
147
+ #
148
+ module ShortMixin
149
+ def self.included(_host)
150
+ ::Object.include(LogShortExt)
54
151
  end
55
- # -----
56
152
  end
57
153
  end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Logger Singleton Class
4
+ module Sinlog
5
+ class Logger
6
+ require 'singleton'
7
+
8
+ include Singleton
9
+ attr_reader :logger
10
+
11
+ # Example:
12
+ #
13
+ # logger = Sinlog::Logger.instance.logger
14
+ # logger.info "Information"
15
+ # logger.debug "This is a debug message"
16
+ #
17
+ # The log output format will be similar to:
18
+ #
19
+ # [INFO] 21:29:22.004 Information
20
+ # [DEBUG] 21:29:22.005 This is a debug message
21
+ #
22
+ # Where "INFO" is highlighted in cyan and "DEBUG" is highlighted in blue.
23
+ #
24
+ # The default log level is set based on the RUBY_LOG environment variable.
25
+ # If this variable is not set, the default level is DEBUG.
26
+ def initialize
27
+ @logger = StdLogger.new($stderr)
28
+ set_level_from_env!
29
+ @logger.formatter = Kernel.proc do |severity, datetime, progname, msg|
30
+ color = COLORS[severity.downcase.to_sym]
31
+ reset = COLORS[:unknown]
32
+ formatted_datetime = datetime.strftime('%H:%M:%S.%L')
33
+ prog = format_prog_name(progname)
34
+ "[#{color}#{severity}#{reset}] #{formatted_datetime} #{prog}#{msg}\n"
35
+ end
36
+ end
37
+
38
+ def self.logger
39
+ instance.logger
40
+ end
41
+
42
+ # Set the `@logger.level` (**log level**) based on the value of an environment variable.
43
+ #
44
+ # If env_name is not specified, it reads the value of the `RUBY_LOG` environment variable.
45
+ #
46
+ # - If the value exists, it is converted to lowercase, then to a symbol, and looked up in the LV hash;
47
+ # - If it does not exist, the default level is DEBUG(0);
48
+ # - If the lookup result is invalid, the level is set to ERROR(3);
49
+ # - If the environment variable value is empty, the lookup result will be invalid,
50
+ # and the level will be set to ERROR(3).
51
+ #
52
+ # Example:
53
+ #
54
+ # ENV["XX_LOG"] = "info" # or setenv in posix-sh: export XX_LOG=info
55
+ # logger = Sinlog::Logger.instance.tap { it.set_level_from_env!("XX_LOG") }.logger
56
+ #
57
+ # logger.debug "This message will not be displayed because the current log level is info"
58
+ # logger.info "Hello!"
59
+ def set_level_from_env!(env_name = 'RUBY_LOG')
60
+ env_str = ENV[env_name]&.downcase || 'debug'
61
+
62
+ Sinlog
63
+ .to_log_level(env_str)
64
+ .then { @logger.level = _1 }
65
+ end
66
+
67
+ private
68
+
69
+ def format_prog_name(progname)
70
+ return '' if progname.to_s.empty?
71
+
72
+ green = "\e[32m"
73
+ reset = "\e[0m"
74
+ space = ' '
75
+ "<#{green}#{progname}#{reset}>#{space}"
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sinlog
4
+ module_function
5
+
6
+ # => Integer
7
+ #
8
+ # == Example
9
+ #
10
+ # require 'sinlog'
11
+ #
12
+ # # values: 'debug', 'info', 'warn', 'error', 'fatal', 'unknown'
13
+ # Sinlog.to_log_level('dbg') #=> LV[:debug] => 0
14
+ # Sinlog.to_log_level('info') #=> LV[:info] => 1
15
+ #
16
+ def to_log_level(level) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
17
+ case level
18
+ when 0..5
19
+ level
20
+ when 'debug', 'dbg', :dbg
21
+ LV[:debug]
22
+ when 'info', 'information'
23
+ LV[:info]
24
+ when 'warn', 'warning'
25
+ LV[:warn]
26
+ when 'err', 'error', :err
27
+ LV[:error]
28
+ when 'fatal'
29
+ LV[:fatal]
30
+ when 'unk', 'unknown', :unk
31
+ LV[:unknown]
32
+ when Symbol
33
+ LV.fetch(level, LV[:error])
34
+ else
35
+ LV[:error]
36
+ end
37
+ end
38
+
39
+ # => Sinlog::Logger.instance
40
+ def instance
41
+ Sinlog::Logger.instance
42
+ end
43
+
44
+ # => ::Logger
45
+ #
46
+ # == English
47
+ #
48
+ # Creates a new ::Logger instance.
49
+ #
50
+ # You can configure the log level through parameters.
51
+ #
52
+ # - env_name
53
+ # - Type: String
54
+ # - Specifies the name of an environment variable.
55
+ # - If set to nil, the program will attempt to read `RUBY_LOG` and set the log level accordingly.
56
+ # - Example: logger(env_name: nil)
57
+ # - If the user runs `RUBY_LOG=debug ./[your-script].rb`
58
+ # - The log level will be set to `debug`.
59
+ # - Example: logger(env_name: "XX_CLI_LOG")
60
+ # - If the user runs `XX_CLI_LOG=warn ./[your-script].rb`
61
+ # - The log level will be set to `warn`.
62
+ #
63
+ # - level
64
+ # - Type: Integer OR String OR Symbol
65
+ # - The level parameter takes precedence over env_name.
66
+ # - If both level and env_name are provided, the program will parse level first and return early.
67
+ #
68
+ # == 中文
69
+ #
70
+ # 创建一个新的 ::Logger 实例。
71
+ #
72
+ # 我们可以通过参数来配置日志级别。
73
+ #
74
+ # - env_name
75
+ # - 类型: String
76
+ # - 指定特定的环境变量名称
77
+ # - 当其为 nil 时,程序默认会尝试获取 RUBY_LOG 的值,并设置日志级别。
78
+ # - 假设 logger(env_name: nil)
79
+ # - 若用户调用 `RUBY_LOG=debug ./[your-script].rb`
80
+ # - 则日志级别为 debug。
81
+ # - 假设 logger(env_name: "XX_CLI_LOG")
82
+ # - 若用户调用 `XX_CLI_LOG=warn ./[your-script].rb`
83
+ # - 则日志级别为 warn。
84
+ # - level
85
+ # - 类型: Integer OR String OR Symbol
86
+ # - level 的优先级要高于 env_name
87
+ # - 若 level 和 env_name 都不为 nil, 则程序会优先解析 level,并提前 return。
88
+ #
89
+ # == Example
90
+ #
91
+ # require 'sinlog'
92
+ #
93
+ # # level values:
94
+ # # - "debug"
95
+ # # - "dbg"
96
+ # # - "info"
97
+ # # - "warn"
98
+ # # - "error"
99
+ # # - "err"
100
+ # # - "fatal"
101
+ # # - Integer (e.g., Sinlog::LV[:debug])
102
+ #
103
+ # log = Sinlog.logger(level: "dbg")
104
+ # log.level == Sinlog::LV[:debug] #=> true
105
+ # a = 3
106
+ # log.debug "a=#{a}"
107
+ #
108
+ # log = Sinlog.logger(level: 'warn')
109
+ # log.level == Sinlog::LV[:warn] #=> true
110
+ # log.error "Failed to open file."
111
+ #
112
+ # ENV["CUSTOM_LOG"] = 'info'
113
+ # log = Sinlog.logger(env_name: "CUSTOM_LOG")
114
+ # log.level == Sinlog::LV[:info] #=> true
115
+ #
116
+ # log = Sinlog.logger(env_name: "CUSTOM_LOG", level: "error")
117
+ # log.level == Sinlog::LV[:error] #=> true
118
+ #
119
+ def logger(env_name: nil, level: nil)
120
+ std_logger = instance.logger
121
+
122
+ # if level != nil
123
+ return std_logger.tap { _1.level = to_log_level(level) } unless level.nil?
124
+
125
+ # if env_name != nil
126
+ instance.set_level_from_env!(env_name) unless env_name.nil?
127
+
128
+ std_logger
129
+ end
130
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sinlog
4
+ # LogShortExt is a module that adds convenient logging methods.
5
+ #
6
+ # Similar to LogExt, but methods omit the `log_` prefix.
7
+ #
8
+ # For example:
9
+ # * `"msg".err` instead of `"msg".log_err`;
10
+ # * `"msg".warn` instead of `"msg".log_warn`
11
+ #
12
+ # We can activate it with `using Sinlog::ShortRefin`
13
+ #
14
+ # == Overview
15
+ #
16
+ # * `dbg` – DEBUG
17
+ # * `info` – INFO
18
+ # * `warn` – WARN
19
+ # * `err` – ERROR
20
+ # * `fatal` – FATAL
21
+ # * `unk` – UNKNOWN
22
+ module LogShortExt
23
+ # Logs the current object at *debug* level using Sinlog.logger
24
+ def dbg
25
+ Sinlog.logger.debug(self)
26
+ end
27
+
28
+ # Logs the current object at *information* level using Sinlog.logger
29
+ def info
30
+ Sinlog.logger.info(self)
31
+ end
32
+
33
+ # Logs the current object at *warning* level using Sinlog.logger
34
+ def warn
35
+ Sinlog.logger.warn(self)
36
+ end
37
+
38
+ # Logs the current object at *error* level using Sinlog.logger
39
+ def err
40
+ Sinlog.logger.error(self)
41
+ end
42
+
43
+ # Logs the current object at *fatal* level using Sinlog.logger
44
+ def fatal
45
+ Sinlog.logger.fatal(self)
46
+ end
47
+
48
+ # Logs the current object at *unknown* level using Sinlog.logger
49
+ def unk
50
+ Sinlog.logger.unknown(self)
51
+ end
52
+ # -----
53
+ end
54
+ private_constant :LogShortExt
55
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Sinlog
4
- VERSION = '0.0.4'
3
+ module Sinlog
4
+ VERSION = '0.0.6'
5
5
  end
data/lib/sinlog.rb CHANGED
@@ -4,17 +4,19 @@
4
4
  #
5
5
  # The following modules provide different ways to add logging capabilities:
6
6
  #
7
- # * Loggable : A mixin module. Include it in your class to add logging methods with the `log_` prefix.
8
- # * LogExt : A refinement. Activate it with `using` to add logging methods with the `log_` prefix.
9
- # * LogShortExt : A refinement. Similar to LogExt, but methods omit the `log_` prefix.
7
+ # * Refin : A refinement. Activate it with `using` to add logging methods with the `log_` prefix.
8
+ # * ShortRefin : A refinement. Similar to `Sinlog::Refin`, but methods omit the `log_` prefix.
9
+ # * Mixin : A mixin module. It's a global object monkey patch, use `include Sinlog::Mixin` with caution.
10
+ # * ShortMixin : A mixin module. Similar to `Sinlog::Mixin`, but methods omit the `log_` prefix.
10
11
  #
11
- # === Comparison Table
12
+ # === Comparison Table (Monkey Patching)
12
13
  #
13
- # Module | Type | Activation | Method Naming
14
- # -------------- | ---------- | ------------ | -------------------------
15
- # Loggable | Mixin | include | log_dbg, log_info, etc.
16
- # LogExt | Refinement | using | log_dbg, log_info, etc.
17
- # LogShortExt | Refinement | using | dbg, info, warn, err, fatal, unk
14
+ # | Module | Type | Activation | Method Naming |
15
+ # | ---------- | ---------- | ---------- | -------------------------------------------------------- |
16
+ # | Mixin | Mixin | include | log_dbg, log_info, log_warn, log_err, log_fatal, log_unk |
17
+ # | Refin | Refinement | using | log_dbg, log_info, log_warn, log_err, log_fatal, log_unk |
18
+ # | ShortMixin | Mixin | include | dbg, info, warn, err, fatal, unk |
19
+ # | ShortRefin | Refinement | using | dbg, info, warn, err, fatal, unk |
18
20
  #
19
21
  # == Examples
20
22
  #
@@ -29,21 +31,31 @@
29
31
  # === Mixin
30
32
  #
31
33
  # require 'sinlog'
32
- # include Sinlog::Loggable
34
+ # include Sinlog::Mixin
35
+ #
33
36
  # "Hello".log_info
37
+ # "World".log_dbg
34
38
  #
35
39
  # === Refinement
36
40
  #
37
41
  # require 'sinlog'
38
- # using Sinlog::LogShortExt
39
- # "Hello".info
42
+ #
43
+ # using Sinlog::Refin
44
+ # "Foo".log_info
45
+ #
46
+ # using Sinlog::ShortRefin
47
+ # "Bar".warn
40
48
  #
41
49
  # Read more: https://github.com/2moe/sinlog-gem
42
- class Sinlog; end
50
+ module Sinlog; end
43
51
 
44
52
  require_relative 'sinlog/version'
45
53
 
46
- require_relative 'sinlog/init'
47
- require_relative 'sinlog/loggable'
54
+ require_relative 'sinlog/consts'
55
+ require_relative 'sinlog/logger'
56
+ require_relative 'sinlog/module_fn'
57
+
48
58
  require_relative 'sinlog/log_ext'
49
- require_relative 'sinlog/log_short_ext'
59
+ require_relative 'sinlog/short_ext'
60
+
61
+ require_relative 'sinlog/loggable'