File: logging.rb

package info (click to toggle)
ruby-neovim 0.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 548 kB
  • sloc: ruby: 4,178; sh: 23; makefile: 4
file content (88 lines) | stat: -rw-r--r-- 2,215 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
require "logger"

module Neovim
  # Mixed into classes for unified logging helper methods.
  #
  # @api private
  module Logging
    TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S.%6N".freeze

    # Return the value of @logger, or construct it from the environment.
    # $NVIM_RUBY_LOG_FILE specifies a file to log to (default +STDERR+), while
    # $NVIM_RUBY_LOG_LEVEL specifies the level (default +WARN+)
    def self.logger(env=ENV)
      return @logger if instance_variable_defined?(:@logger)

      env_file, env_level =
        env.values_at("NVIM_RUBY_LOG_FILE", "NVIM_RUBY_LOG_LEVEL")

      @logger = Logger.new(env_file || STDERR)

      if /\S+/.match?(env_level)
        begin
          @logger.level = Integer(env_level)
        rescue ArgumentError
          @logger.level = Logger.const_get(env_level.upcase)
        end
      else
        @logger.level = Logger::WARN
      end

      @logger.formatter = json_formatter
      @logger
    end

    def self.logger=(logger)
      logger.formatter = json_formatter
      @logger = logger
    end

    def self.included(base)
      base.send(:include, Helpers)
    end

    def self.json_formatter
      lambda do |level, time, _, fields|
        require "multi_json"

        MultiJson.encode(
          {
            _level: level,
            _time: time.strftime(TIMESTAMP_FORMAT)
          }.merge!(fields)
        ) << "\n"
      end
    end
    private_class_method :json_formatter

    # @api private
    module Helpers
      private

      def log(level, method=nil, &block)
        begin
          Logging.logger.public_send(level) do
            {
              _class: self.class,
              _method: method || block.binding.eval("__method__")
            }.merge!(yield)
          end
        rescue => ex
          Logging.logger.error("failed to log: #{ex.inspect}")
        end
      rescue
        # Inability to log shouldn't abort process
      end

      def log_exception(level, ex, method)
        log(level, method) do
          {exception: ex.class, message: ex.message}
        end

        log(:debug, method) do
          {exception: ex.class, message: ex.message, backtrace: ex.backtrace}
        end
      end
    end
  end
end