evanescent 1.0.0
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.
- checksums.yaml +7 -0
- data/lib/evanescent.rb +122 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e9756a1c8493afab25b856431ec5359429ec7a36
|
4
|
+
data.tar.gz: 7a649af3f5758d2d7d8bb180787d8ff334ab30c1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 22f7837d5e81ea7e90fa53b490a838a95f3ce8b865aa4b962fa86ce6cb3ac1d47deecfa0d09110b1b7e36fc7e77e72e319a255598e629cf0df46998d929583d7
|
7
|
+
data.tar.gz: 4af0198e703e5972b924a6ad1d8f70ab32eb4942c18674b962c0a5a754a84d44040f430ae9b1870e23d476c0b14ccf8133f7b3d697dec5852f07950b8de8c211
|
data/lib/evanescent.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'chronic_duration'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'zlib'
|
4
|
+
|
5
|
+
# 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:
|
6
|
+
#* Rotation by time / date.
|
7
|
+
#* Compression of old files.
|
8
|
+
#* Removal of old compressed files.
|
9
|
+
# Its purpuse is to supplement logging classes, allowing everything related to logging management, to be done within Ruby, without relying on external tools (such as logrotate).
|
10
|
+
class Evanescent
|
11
|
+
# Current path being written to.
|
12
|
+
attr_reader :path
|
13
|
+
|
14
|
+
# Rotation policy.
|
15
|
+
attr_reader :rotation
|
16
|
+
|
17
|
+
# How long rotated files are kept (in seconds).
|
18
|
+
attr_reader :keep
|
19
|
+
|
20
|
+
# Must receive a Hash with:
|
21
|
+
# +:path+:: Path where to write to.
|
22
|
+
# +:rotation+:: Either +:hourly+ or +:daily+.
|
23
|
+
# +:keep+:: For how long to keep rotated files. It is parsed with ChronicDuration's natural language features. Examples: '1 day', '1 month'.
|
24
|
+
def initialize opts
|
25
|
+
@path = opts[:path]
|
26
|
+
@rotation = opts[:rotation]
|
27
|
+
@keep = ChronicDuration.parse(opts[:keep])
|
28
|
+
@mutex = Mutex.new
|
29
|
+
@last_prefix = make_prefix(Time.now)
|
30
|
+
open_file
|
31
|
+
end
|
32
|
+
|
33
|
+
# Writes to #path and rotate, compress and purge if necessary.
|
34
|
+
def write string
|
35
|
+
@mutex.synchronize do
|
36
|
+
rotate
|
37
|
+
compress
|
38
|
+
purge
|
39
|
+
@io.write(string)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Close file.
|
44
|
+
def close
|
45
|
+
@mutex.synchronize do
|
46
|
+
@io.close
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def open_file
|
53
|
+
@io = File.open(path, File::APPEND | File::CREAT | File::WRONLY)
|
54
|
+
@io.sync = true
|
55
|
+
end
|
56
|
+
|
57
|
+
PARAMS = {
|
58
|
+
hourly: {
|
59
|
+
strftime: '%Y%m%d%H',
|
60
|
+
glob: '[0-9]' * (4 + 2 * 3)
|
61
|
+
},
|
62
|
+
daily: {
|
63
|
+
strftime: '%Y%m%d',
|
64
|
+
glob: '[0-9]' * (4 + 2 * 2)
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
def make_prefix time
|
69
|
+
time.strftime(PARAMS[rotation][:strftime])
|
70
|
+
end
|
71
|
+
|
72
|
+
def rotate
|
73
|
+
curr_suffix = make_prefix(Time.now)
|
74
|
+
if curr_suffix != @last_prefix
|
75
|
+
@io.close
|
76
|
+
rotated = "#{path}.#{curr_suffix}"
|
77
|
+
begin
|
78
|
+
FileUtils.mv(path, rotated)
|
79
|
+
rescue
|
80
|
+
warn("Error renaming '#{path}' to '#{rotated}': #{$!}")
|
81
|
+
end
|
82
|
+
open_file
|
83
|
+
@last_prefix = curr_suffix
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def compress
|
88
|
+
Dir.glob("#{path}.#{PARAMS[rotation][:glob]}").each do |uncompressed|
|
89
|
+
compressed = "#{uncompressed}.gz"
|
90
|
+
Zlib::GzipWriter.open(compressed) do |gz|
|
91
|
+
gz.mtime = File.mtime(uncompressed)
|
92
|
+
gz.orig_name = uncompressed
|
93
|
+
File.open(uncompressed, 'r') do |io|
|
94
|
+
io.binmode
|
95
|
+
io.each do |data|
|
96
|
+
gz.write(data)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
File.delete(uncompressed)
|
101
|
+
end
|
102
|
+
rescue
|
103
|
+
warn("Error compressing files: #{$!}")
|
104
|
+
end
|
105
|
+
|
106
|
+
def purge
|
107
|
+
Dir.glob("#{path}.#{PARAMS[rotation][:glob]}.gz").each do |compressed|
|
108
|
+
time_extractor = Regexp.new(
|
109
|
+
'^' + Regexp.escape("#{path}.") + "(?<time>.+)" + Regexp.escape(".gz") + '$'
|
110
|
+
)
|
111
|
+
time_string = compressed.match(time_extractor)[:time]
|
112
|
+
compressed_time = Time.strptime(time_string, PARAMS[rotation][:strftime])
|
113
|
+
age = Time.now - compressed_time
|
114
|
+
if age > keep
|
115
|
+
File.delete(compressed)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
rescue
|
119
|
+
warn("Error purging old files: #{$!}")
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evanescent
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Fabio Pugliese Ornellas
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-11-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: chronic_duration
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.10'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.10.6
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.10'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.10.6
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rspec
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '3.3'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.3'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: guard-rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '4.6'
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 4.6.4
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '4.6'
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 4.6.4
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rake
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '10.4'
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 10.4.2
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '10.4'
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 10.4.2
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
name: simplecov
|
89
|
+
requirement: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - "~>"
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0.10'
|
94
|
+
type: :development
|
95
|
+
prerelease: false
|
96
|
+
version_requirements: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - "~>"
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0.10'
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
name: timecop
|
103
|
+
requirement: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - "~>"
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0.8'
|
108
|
+
type: :development
|
109
|
+
prerelease: false
|
110
|
+
version_requirements: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - "~>"
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0.8'
|
115
|
+
description: |-
|
116
|
+
This gem provides an 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:
|
117
|
+
* Rotation by time / date.
|
118
|
+
* Compression of old files.
|
119
|
+
* Removal of old compressed files.
|
120
|
+
Its purpuse is to supplement logging classes, allowing everything related to logging management, to be done within Ruby, without relying on external tools (such as logrotate).
|
121
|
+
email: fabio.ornellas@gmail.com
|
122
|
+
executables: []
|
123
|
+
extensions: []
|
124
|
+
extra_rdoc_files: []
|
125
|
+
files:
|
126
|
+
- lib/evanescent.rb
|
127
|
+
homepage: https://github.com/fornellas/evanescent
|
128
|
+
licenses:
|
129
|
+
- GPLv3
|
130
|
+
metadata: {}
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 2.4.5
|
148
|
+
signing_key:
|
149
|
+
specification_version: 4
|
150
|
+
summary: IO like object that allows logging rotation, compression and purging.
|
151
|
+
test_files: []
|