Class: Evanescent

Inherits:
Object
  • Object
show all
Defined in:
lib/evanescent.rb

Overview

IO like object, that can be used with any logging class (such as Ruby’s native Logger). This object will save its input to a file, and allows:

  • Hourly or daily rotation.

  • Compression of rotated files.

  • Removal of old compressed files.

This functionality supplement logging classes, allowing everything related to logging management, to be done within Ruby, without relying on external tools (such as logrotate).

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Evanescent

Must receive a Hash with:

:path

Path where to write to.

:rotation

Either :hourly or :daily.

:keep

For how long to keep rotated files. It is parsed with chronic_duration Gem natural language features. Examples: ‘1 day’, ‘1 month’.



37
38
39
40
41
42
43
44
45
# File 'lib/evanescent.rb', line 37

def initialize opts
  @path = opts[:path]
  @rotation = opts[:rotation]
  @keep = ChronicDuration.parse(opts[:keep])
  @mutex = Mutex.new
  @last_prefix = make_suffix(Time.now)
  @io = nil
  @compress_thread = nil
end

Instance Attribute Details

#keepObject (readonly)

How long rotated files are kept (in seconds).



20
21
22
# File 'lib/evanescent.rb', line 20

def keep
  @keep
end

#pathObject (readonly)

Current path being written to.



14
15
16
# File 'lib/evanescent.rb', line 14

def path
  @path
end

#rotationObject (readonly)

Rotation policy.



17
18
19
# File 'lib/evanescent.rb', line 17

def rotation
  @rotation
end

Class Method Details

.logger(opts) ⇒ Object

Shortcut for: Logger.new(Evanescent.new(opts)). Requires logger if needed.



24
25
26
27
28
29
30
31
# File 'lib/evanescent.rb', line 24

def self.logger opts
  unless Object.const_defined? :Logger
    require 'logger'
  end
  Logger.new(
    self.new(opts)
  )
end

Instance Method Details

#closeObject

Close file.



70
71
72
73
74
# File 'lib/evanescent.rb', line 70

def close
  @mutex.synchronize do
    @io.close
  end
end

#wait_compressionObject

Compression is done in a separate thread. This method suspends current thread execution until existing compression thread returns. If no compression thread is running, returns immediately.



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/evanescent.rb', line 77

def wait_compression
  if @compress_thread
    begin
      @compress_thread.join
    rescue
      warn("Compression thread failed: #{$!} (#{$!.class})")
    ensure
      @compress_thread = nil
    end
  end
end

#write(string) ⇒ Object

Writes to #path and rotate, compress and purge if necessary.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/evanescent.rb', line 48

def write string
  @mutex.synchronize do
    if new_path = rotation_path
      # All methods here must have exceptions threated. See:
      # https://github.com/ruby/ruby/blob/3e92b635fb5422207b7bbdc924e292e51e21f040/lib/logger.rb#L647
      purge
      mv_path(new_path)
      compress
    end
    open_io
    if @io
      # No exceptions threated here, they should be handled by caller. See:
      # https://github.com/ruby/ruby/blob/3e92b635fb5422207b7bbdc924e292e51e21f040/lib/logger.rb#L653
      @io.write(string)
    else
      warn("Unable to log: '#{path}' not open!")
      0
    end
  end
end