evanescent 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/evanescent.rb +122 -0
  3. 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: []