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.
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: []