simple_rotate 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 57afd4b6d133d914743e6d548507323c5f6f9926
4
- data.tar.gz: a5a6cf55f8e7894d9c7c090a7f0b429161aad2c9
3
+ metadata.gz: 481428ce2f0316a88fabc15531a03bb722641a86
4
+ data.tar.gz: 482f5c5d2154f63ef017817941e049ed7078dff3
5
5
  SHA512:
6
- metadata.gz: 220d55fbab5182dcc7a767113c35b948c9d10c58f23b18e1fe66ff7b5570ebb550964aea5ed5df6f603585dfe2939049db366f51b59d9c4940c9f242badc3fc6
7
- data.tar.gz: f66d8796b8f5cb125541041a621363fdaba0431c81c47e666b43c65f0ed5274dea1a1aa6f5077a37a887242e8d60e63fc466d2e0ed155503847bcf09b5846ad8
6
+ metadata.gz: 50bdabad14095319c3caaeb70df3c5ed79b6a76d637ba7a44863fd644e018624c4afb43aa5f633635a86b5250a54b53ce7cb80d29c8663d4394dd50270f7207e
7
+ data.tar.gz: 80d19f35402ae0aabc0e099986b2dda5f68efe8b7f3b5f0228628a4c16229ecf24238e743f8068c4531324836270503b6c6e5beed3798a15a3630579cc66963e
@@ -1,1127 +1,6 @@
1
- # SimpleRotate - simple logger for ruby
2
- # @autor: Kazuya Hotta (nyanko)
1
+ # SimpleRotate
3
2
  #
4
- require "singleton"
5
- require "monitor"
6
-
7
- class SimpleRotate
8
- VERSION = "1.0.0"
9
- include Singleton
10
- include MonitorMixin
11
-
12
- #----------------
13
- # modlues
14
- #----------------
15
- module LogLevel
16
- LOG_LEVEL_5 = "FATAL"
17
- LOG_LEVEL_4 = "ERROR"
18
- LOG_LEVEL_3 = "WARN"
19
- LOG_LEVEL_2 = "INFO"
20
- LOG_LEVEL_1 = "DEBUG"
21
- LEVEL_ID_FATAL = 5
22
- LEVEL_ID_ERROR = 4
23
- LEVEL_ID_WARN = 3
24
- LEVEL_ID_INFO = 2
25
- LEVEL_ID_DEBUG = 1
26
- end
27
- include LogLevel
28
-
29
- module RotateTerm
30
- TERM_DAILY = 1
31
- TERM_WEEKLY = 7
32
- TERM_MONTHLY = 30
33
- end
34
- include RotateTerm
35
-
36
- module Validator
37
- def valid_file_name
38
- # stdout only
39
- if @file_name.is_a?(Symbol) && @file_name == :STDOUT
40
- @only_stdout = true
41
- return true
42
- end
43
-
44
- # not string
45
- if !@file_name.is_a?(String)
46
- SimpleRotate::Error.argv("file_name", @file_name)
47
- end
48
-
49
- # directory?
50
- if File.directory?(@file_name)
51
- msg = "ERROR => #{@file_name} is a Directory!"
52
- SimpleRotate::Error.warning(msg)
53
- SimpleRotate::Error.argv("file_name", @file_name)
54
- end
55
-
56
- return true
57
- end
58
-
59
- def valid_int(param, argv)
60
- if !argv.is_a?(Integer)
61
- SimpleRotate::Error.argv(param, argv)
62
-
63
- elsif argv < 0
64
- msg = %{You can't specify the negative value!}
65
- SimpleRotate::Error.warning(msg)
66
- SimpleRotate::Error.argv(param, argv)
67
- end
68
- end
69
-
70
- def valid_bool(param, argv)
71
- argv = true if argv == 1
72
- argv = false if argv == 0
73
- if !(argv.instance_of?(TrueClass) || argv.instance_of?(FalseClass))
74
- SimpleRotate::Error.argv(param, argv)
75
- end
76
- return true
77
- end
78
- end
79
- include Validator
80
-
81
- #----------------
82
- # classes
83
- #----------------
84
- #
85
- # error class for SimpleRotate
86
- #
87
- class Error < RuntimeError
88
- msg = "aborted the log file rotation process,"
89
- msg += " because an unexpected error has occured."
90
- ROTATION_FAILED = msg
91
-
92
- @@silence = false
93
-
94
- #
95
- # skip warning message
96
- #
97
- def self.silence
98
- @@silence = true
99
- end
100
-
101
- #
102
- # argument error
103
- #
104
- def self.argv(param, argv)
105
- msg = "'#{param}'='#{argv}' is invalid argument value!"
106
- self.throw_error(msg)
107
- end
108
-
109
- #
110
- # method missing
111
- #
112
- def self.missing(name)
113
- msg = "undifined method 'SimpleRotate##{name}'"
114
- self.throw_error(msg)
115
- end
116
-
117
- #
118
- # file open error
119
- #
120
- def self.open(name)
121
- msg = "Couldn't open a '#{name}'"
122
- self.throw_error(msg)
123
- end
124
-
125
- #
126
- # load error
127
- #
128
- def self.load(name)
129
- msg = "Couldn't load a '#{name}'"
130
- self.throw_error(msg)
131
- end
132
-
133
- #
134
- # exist error
135
- #
136
- def self.exist(name, type)
137
- msg = "Already exists this #{type} => '#{name}'"
138
- self.throw_error(msg)
139
- end
140
-
141
- #
142
- # warning - don't throw error
143
- #
144
- def self.warning(msg)
145
- warn "[WARNING] #{msg} - (SimpleRotate::Error)" if !@@silence
146
- end
147
-
148
- # @param msg string
149
- #
150
- def self.throw_error(msg)
151
- exeption = self.new(msg)
152
- warn exeption.message if !@@silence
153
- raise SimpleRotate::Error
154
- end
155
- end
156
-
157
- #
158
- # The module for the process safe
159
- # This module will be included by ProcessSync class
160
- #
161
- module ProcessSyncMixin
162
- @@scheduled_del_lockfile = false
163
- @@tempf_name = nil
164
- @@tempf = nil
165
-
166
- def locked?
167
- return false if !tempf_exists?
168
-
169
- # return false, if locked by another
170
- status = @@tempf.flock(File::LOCK_EX | File::LOCK_NB)
171
-
172
- return status == false
173
- end
174
-
175
- # lock the temp file
176
- def lock
177
- create_tempfile if !tempf_exists?
178
-
179
- # if don't reopen temp file, can't lock...
180
- reopen_temp_file
181
-
182
- cnt = 0
183
- begin
184
- @@tempf.flock(File::LOCK_EX)
185
-
186
- rescue
187
- cnt += 1
188
- if (cnt <= @try_limit)
189
- sleep(0.5)
190
- create_tempfile if !tempf_exists?
191
- retry
192
- else
193
- SimpleRotate::Error.warning("It was not possible to lock (tried 3times) => #{@@tempf_name}")
194
- return false
195
- end
196
- end
197
- end
198
-
199
- # unlock the temp file
200
- def unlock
201
- return nil if !tempf_exists?
202
-
203
- begin
204
- @@tempf.flock(File::LOCK_UN)
205
- rescue
206
- SimpleRotate::Error.warning("It was not possible to unlock => #{@@tempf_name}")
207
- end
208
- end
209
- end
210
-
211
- #
212
- # The classes for process-safe
213
- #
214
- class ProcessSync
215
- include ProcessSyncMixin
216
-
217
- ProcessSyncMixin.instance_methods.each do |method_name|
218
- method = instance_method(method_name)
219
- define_method(method_name) do |*args|
220
- ###################
221
- # common execution
222
- ###################
223
- # Processing to be performed at the beginning of the method
224
- return nil if !@enable
225
- ###################
226
- method.bind(self).call(*args)
227
- end
228
- end
229
-
230
- def initialize(sr)
231
- @sr = sr
232
- @enable = sr.instance_variable_get(:@psafe_mode)
233
- @file_name = sr.instance_variable_get(:@file_name)
234
-
235
- # #init not called
236
- return self if @file_name == nil
237
-
238
- @logf = sr.instance_variable_get(:@logf)
239
- @try_limit = 3
240
- @@tempf_name = File.dirname(@file_name) + File::SEPARATOR + ".SimpleRotate_tempfile_#{File.basename($0)}"
241
-
242
- create_tempfile if @enable && !@@scheduled_del_lockfile
243
- end
244
-
245
- # Create the temp file for locking
246
- private
247
- def create_tempfile
248
- if File.exist?(@@tempf_name)
249
- open_temp_file
250
- return nil
251
- end
252
-
253
- begin
254
- @@tempf = File.open(@@tempf_name, File::RDWR|File::CREAT|File::EXCL)
255
-
256
- rescue
257
- SimpleRotate::Error.warning("Couldn't create temp file => #{@@tempf_name}")
258
-
259
- ensure
260
- set_delete_tempfile
261
- end
262
- end
263
-
264
- private
265
- def tempf_exists?
266
- return File.exist?(@@tempf_name)
267
- end
268
-
269
- # Delete the lock file at the end of the script
270
- private
271
- def set_delete_tempfile
272
- return true if @@scheduled_del_lockfile
273
-
274
- if File.exists?(@@tempf_name)
275
- # is it empty?
276
- if File.size(@@tempf_name) == 0
277
- delete_at_end
278
- else
279
- # it is not empty
280
- msg = "File is not empty => #{@@tempf_name}#{$-0}"
281
- msg += "Skip to delete temp file!"
282
- SimpleRotate::Error.warning(msg)
283
- end
284
- end
285
- @@scheduled_del_lockfile = true
286
- end
287
-
288
- private
289
- def delete_at_end
290
- at_exit do
291
- begin
292
- File.delete(@@tempf_name)
293
- rescue
294
- #SimpleRotate::Error.warning("Couldn't delete temp file => #{@@tempf_name}")
295
- end
296
- end
297
- end
298
-
299
- private
300
- def reopen_temp_file
301
- close_temp_file
302
- open_temp_file
303
- end
304
-
305
- private
306
- def open_temp_file
307
- if @@tempf.is_a?(IO) && @@tempf.closed? || !@@tempf.is_a?(IO)
308
- begin
309
- @@tempf = File.open(@@tempf_name, File::RDWR|File::CREAT|File::APPEND)
310
- rescue
311
- SimpleRotate::Error.warning("Couldn't open temp file => #{@@tempf_name}")
312
- end
313
- end
314
- end
315
-
316
- private
317
- def close_temp_file
318
- if @@tempf.is_a?(IO) && !@@tempf.closed?
319
- begin
320
- @@tempf.close
321
- rescue
322
- SimpleRotate::Error.warning("Couldn't close temp file => #{@@tempf_name}")
323
- end
324
- end
325
- end
326
- end
327
-
328
- #--------------------
329
- # access definitions
330
- #--------------------
331
- attr_accessor :threshold,
332
- :date_format,
333
- :logging_format,
334
- :rename_format,
335
- :allow_overwrite,
336
- :sleep_time
337
-
338
- attr_reader :limit
339
-
340
- #----------------
341
- # public methods
342
- #----------------
343
- #
344
- # return method missing error
345
- #
346
- def method_missing(name, *argv)
347
- SimpleRotate::Error.missing(name)
348
- end
349
-
350
- #
351
- # @param string|symbol $file_name
352
- # @param string|int $limit
353
- # @param int $rotation
354
- # @return self
355
- #
356
- def init(file_name=File.absolute_path($0+".log"), limit='1M', rotation=0)
357
- @file_name = file_name
358
- @limit = limit
359
- @rotation = rotation
360
-
361
- # load defaults
362
- include_defaults
363
-
364
- # validation
365
- valid_file_name
366
- valid_int("rotation", @rotation)
367
-
368
- # stdout only
369
- return self if @only_stdout
370
-
371
- if rotate_by_term?
372
- # term rotation
373
- set_days_cnt_of_term
374
- @limit_term = @limit
375
- @rotate_by_term = true
376
-
377
- else
378
- # file_size rotation
379
- @limit_size = trim_byte(@limit)
380
- if @limit_size <= 0
381
- SimpleRotate::Error.argv("limit", @limit)
382
- end
383
- @rotate_by_term = false
384
- end
385
-
386
- # for process safe
387
- @psync = ProcessSync.new(self)
388
-
389
- # open or generate the log file
390
- synchronize do
391
- @psync.lock
392
-
393
- prepare_logf
394
-
395
- @psync.unlock
396
- end
397
-
398
- # if block given, colse IO
399
- if defined? yield
400
- yield self
401
- e
402
- end
403
-
404
- return self
405
- end
406
-
407
- #
408
- # log message out to STDOUT when use SimpleRotate#w method
409
- #
410
- def with_stdout
411
- @with_stdout = true
412
- end
413
-
414
- #
415
- # enable compress
416
- #
417
- def compress
418
- @compress = true
419
- use_zlib
420
- end
421
-
422
- #
423
- # define the compression level
424
- # this method load 'zlib'
425
- # this method enable compress flag
426
- # @param int level - 0-9
427
- # default is 6
428
- #
429
- def compress_level(level)
430
- @compress_level = level
431
- valid_int("compress_level", @compress_level)
432
- compress
433
-
434
- return level
435
- end
436
-
437
- #
438
- # @param string $log message write to log file
439
- # @return string
440
- #
441
- def w(log)
442
- if @file_name == nil
443
- msg = "file_name is Nil Class! Please call #init method"
444
- SimpleRotate::Error.throw_error(msg)
445
- end
446
-
447
- # don't out log message if Doesn't reach threshold
448
- return nil if (!over_threshold?)
449
-
450
- content = get_trimmed_log(log)
451
-
452
- # return and end func, if only_stdout enable
453
- if @only_stdout
454
- puts content
455
- return log
456
- end
457
-
458
- # write message to file
459
- synchronize do
460
- @psync.lock
461
-
462
- sync_inode
463
- @logf.puts(content)
464
- @logf.flush if @enable_wflush
465
- @logf.fsync if @enable_wflush
466
-
467
- @psync.unlock
468
- end
469
-
470
- # dump log message STDOUT, if with_stdout enable
471
- puts content if @with_stdout
472
-
473
- # rotate if necessary
474
- rotate_if if !@no_wcheck
475
-
476
- return log
477
- end
478
-
479
- #
480
- # disable call File#flush after #w method
481
- #
482
- def enable_wflush
483
- @enable_wflush = true
484
- end
485
-
486
- #
487
- # enable call File#flush after #w method
488
- #
489
- def disable_wflush
490
- @enable_wflush = false
491
- end
492
-
493
- #
494
- # close file
495
- #
496
- def e
497
- return nil if logf_not_usable
498
-
499
- synchronize do
500
- @psync.lock
501
-
502
- @logf.close
503
-
504
- @psync.unlock
505
- end
506
- end
507
-
508
- #
509
- # file reopen
510
- #
511
- def reopen
512
- return nil if logf_not_usable
513
-
514
- if !file_closed?
515
- SimpleRotate::Error.warning("File is already open!")
516
- return nil
517
- end
518
-
519
- openadd
520
- return @logf
521
- end
522
-
523
- #
524
- # force rotation
525
- #
526
- def flush
527
- return nil if logf_not_usable
528
- return nil if @rotate_by_term
529
- rotation(:FLUSH)
530
- end
531
-
532
- #
533
- # don't check can to rotate at #w method
534
- #
535
- def no_wcheck
536
- @no_wcheck = true
537
- end
538
-
539
- #
540
- # is log file open?
541
- # @return nil|bool
542
- #
543
- def file_closed?
544
- return nil if logf_not_usable
545
- return @logf.closed?
546
- end
547
-
548
- #
549
- # skip warning message
550
- #
551
- def silence
552
- SimpleRotate::Error.silence
553
- end
554
-
555
- #
556
- # set log level FATAL
557
- # @return self
558
- #
559
- def fatal
560
- @log_level = 5
561
- return self
562
- end
563
-
564
- #
565
- # set log level ERROR
566
- # @return self
567
- #
568
- def error
569
- @log_level = 4
570
- return self
571
- end
572
-
573
- #
574
- # set log level WORN
575
- # @return self
576
- #
577
- def warn
578
- @log_level = 3
579
- return self
580
- end
581
-
582
- #
583
- # set log level INFO
584
- # @return self
585
- #
586
- def info
587
- @log_level = 2
588
- return self
589
- end
590
-
591
- #
592
- # set log level DEBUG
593
- # @return self
594
- #
595
- def debug
596
- @log_level = 1
597
- return self
598
- end
599
-
600
- #
601
- # try to be a safe process
602
- #
603
- def psafe_mode(sleep_time=0.1)
604
- @psafe_mode = true
605
- @enable_wflush = true
606
- @sleep_time = sleep_time
607
-
608
- @psync = ProcessSync.new(self)
609
- end
610
-
611
- #
612
- # Reopen file necessary
613
- # @return bool|nil
614
- #
615
- def sync_inode
616
- return nil if logf_not_usable
617
-
618
- cnt = 0
619
- begin
620
- # check i-node number
621
- open_inode = @logf.stat.ino
622
- logf_inode = File.stat(@file_name).ino
623
- raise if open_inode != logf_inode
624
- rescue
625
- cnt += 1
626
- sleep(0.1)
627
- e
628
- openadd
629
-
630
- if cnt <= @sync_inode_limit
631
- retry
632
- else
633
- SimpleRotate::Error.warning(%{inode number didn't not match, tried #{cnt} times!})
634
- return false
635
- end
636
- end
637
-
638
- return true
639
- end
640
-
641
- #
642
- # Disable #sync_inode
643
- #
644
- def no_sync_inode
645
- @no_sync_inode = true
646
- end
647
-
648
- #----------------
649
- # private methods
650
- #----------------
651
- #
652
- # log file is not IO class or stdout only
653
- # @return bool
654
- #
655
- private
656
- def logf_not_usable
657
- !@logf.is_a?(IO) || @only_stdout
658
- end
659
-
660
- #
661
- # load zlib lib
662
- #
663
- private
664
- def use_zlib
665
- begin
666
- require "zlib"
667
- @compress_level = Zlib::DEFAULT_COMPRESSION if @compress_level == nil
668
-
669
- rescue LoadError
670
- SimpleRotate::Error.load("zlib")
671
- end
672
- end
673
-
674
- #
675
- # open or generate the log file
676
- #
677
- private
678
- def prepare_logf
679
- if File.exist?(@file_name)
680
- # open the exists file, add mode
681
- openadd
682
-
683
- # rotate it if necessary
684
- rotate_if
685
-
686
- else
687
- gen_new_logf
688
- end
689
- end
690
-
691
- #
692
- # generate new log file
693
- #
694
- private
695
- def gen_new_logf
696
- begin
697
- @logf = File.open(@file_name, File::RDWR|File::CREAT|File::TRUNC)
698
- gtime = Time.new.to_i
699
- @logf.puts("created@#{gtime}@Please don't delete this line")
700
- @logf.close
701
-
702
- rescue
703
- SimpleRotate::Error.open(@file_name)
704
- end
705
-
706
- openadd
707
- end
708
-
709
- #
710
- # if file or directory exist, call error
711
- #
712
- private
713
- def exist_error(file)
714
- SimpleRotate::Error.exist(file, "File") if File.exist?(file)
715
- SimpleRotate::Error.exist(file, "Directory") if Dir.exist?(file)
716
-
717
- return true
718
- end
719
-
720
- #
721
- # define default instance vars
722
- #
723
- private
724
- def include_defaults
725
- que = []
726
- que << [%{@threshold}, %{LOG_LEVEL_2}]
727
- que << [%{@log_level}, %{2}]
728
- que << [%{@logging_format}, %{"[$DATE] - $LEVEL : $LOG"}]
729
- que << [%{@date_format}, %{"%Y/%m/%d %H:%M:%S"}]
730
- que << [%{@term_format}, %{"%Y%m%d"}]
731
- que << [%{@rename_format}, %{"."}]
732
- que << [%{@with_stdout}, %{false}]
733
- que << [%{@only_stdout}, %{false}]
734
- que << [%{@no_wcheck}, %{false}]
735
- que << [%{@sync_inode_limit}, %{3}]
736
- que << [%{@no_sync_inode}, %{false}]
737
- que << [%{@enable_wflush}, %{false}]
738
- que << [%{@compress}, %{false}]
739
- que << [%{@psafe_mode}, %{false}]
740
- que << [%{@sleep_time}, %{0}]
741
-
742
- que.each do |q|
743
- if eval(%{#{q[0]} == nil})
744
- eval(%{#{q[0]} = #{q[1]}})
745
- end
746
- end
747
- end
748
-
749
- #
750
- # Whether to rotate by file age?
751
- # @return bool
752
- #
753
- private
754
- def rotate_by_term?
755
- if @limit.is_a?(Integer)
756
- return false
757
-
758
- elsif @limit.is_a?(String)
759
- return @limit.to_i == 0
760
-
761
- else
762
- SimpleRotate::Error.argv("limit", @limit)
763
- end
764
- end
765
-
766
- #
767
- # Open the log file, add mode
768
- #
769
- private
770
- def openadd
771
- @logf = File.open(@file_name, File::RDWR|File::CREAT|File::APPEND)
772
-
773
- # refresh object
774
- @psync = ProcessSync.new(self)
775
- end
776
-
777
- #
778
- # get cretated time of the log file
779
- # @return Time
780
- #
781
- private
782
- def get_logf_generate_time
783
- pos = @logf.pos
784
- begin
785
- @logf.rewind
786
- stamp = @logf.readline.split("@")
787
- @logf.seek(pos)
788
- gtime = Time.at(stamp[1].to_i)
789
-
790
- rescue StandardError, SyntaxError
791
- msg = "Can't get file creation time!"
792
- gtime = Time.now
793
- SimpleRotate::Error.warning(msg)
794
- end
795
-
796
- return gtime
797
- end
798
-
799
- #
800
- # @return int
801
- #
802
- private
803
- def set_days_cnt_of_term
804
- begin
805
- @dayc = eval("TERM_#{@limit}")
806
- rescue NameError
807
- SimpleRotate::Error.argv("limit", @limit)
808
- end
809
- end
810
-
811
- #
812
- # log file size over 'limit_size'?
813
- # @return bool|nil
814
- #
815
- private
816
- def over_size?
817
- return nil if logf_not_usable
818
-
819
- begin
820
- rst = File.size(@file_name) > @limit_size
821
- rescue
822
- rst = false
823
- end
824
-
825
- return rst
826
- end
827
-
828
- private
829
- def safe_over_size?
830
- rst = nil
831
- synchronize do
832
- @psync.lock
833
- rst = over_size?
834
- @psync.unlock
835
- end
836
-
837
- return rst
838
- end
839
-
840
- #
841
- # logfile's elapsed days is over limit?
842
- # @return bool
843
- #
844
- private
845
- def over_term?
846
- return nil if logf_not_usable
847
-
848
- begin
849
- now_time = Time.now
850
- gen_time = get_logf_generate_time
851
- estimated_time = gen_time + (60 * 60 * 24 * @dayc)
852
- rst = estimated_time <= now_time
853
- rescue
854
- rst = false
855
- end
856
-
857
- return rst
858
- end
859
-
860
- private
861
- def safe_over_term?
862
- rst = nil
863
- synchronize do
864
- @psync.lock
865
- rst = over_term?
866
- @psync.unlock
867
- end
868
-
869
- return rst
870
- end
871
-
872
- #
873
- # Format the text for logging
874
- # the following characters are recognized
875
- # $DATE => date
876
- # $LEVEL => log's severity
877
- # $LOG => your log message
878
- # $PID => process ID
879
- # $FILE => execute file name
880
- #
881
- # @param string $log
882
- # @return string
883
- #
884
- private
885
- def get_trimmed_log(log)
886
- log = log.to_s
887
- date = Time.now.strftime(@date_format)
888
- level = eval("LOG_LEVEL_#{@log_level}")
889
- return @logging_format.gsub("$DATE", date)
890
- .gsub("$LEVEL", level)
891
- .gsub("$LOG", log)
892
- .gsub("$PID", $$.to_s)
893
- .gsub("$FILE-FUL", File.absolute_path($0))
894
- .gsub("$FILE", File.basename($0))
895
- end
896
-
897
- #
898
- # Whether that is the output of the log level that exceeds the threshold
899
- # @return boolean
900
- #
901
- private
902
- def over_threshold?
903
- begin
904
- return (@log_level >= eval("LEVEL_ID_#{@threshold}"))
905
- rescue NameError
906
- SimpleRotate::Error.argv("threshold", @threshold)
907
- end
908
- end
909
-
910
- #
911
- # need rotate?
912
- # @return bool
913
- #
914
- private
915
- def reached_limit?(mode=:NO_LOCK)
916
- # file age rotation
917
- if @rotate_by_term
918
- is_over_term = nil
919
- if mode == :NO_LOCK
920
- is_over_term = over_term?
921
- elsif mode == :LOCK
922
- is_over_term = safe_over_term?
923
- end
924
-
925
- return is_over_term
926
- end
927
-
928
- # file size rotation
929
- is_over_size = nil
930
- if mode == :NO_LOCK
931
- is_over_size = over_size?
932
- elsif mode == :LOCK
933
- is_over_size = safe_over_size?
934
- end
935
-
936
- return is_over_size
937
- end
938
-
939
- #
940
- # Rotates as necessary
941
- # @return bool
942
- #
943
- private
944
- def rotate_if
945
- if reached_limit?(:LOCK)
946
- rotation
947
- return true
948
-
949
- else
950
- # no need to rotate
951
- return false
952
- end
953
- end
954
-
955
- #
956
- # prepare & call #do_rotation
957
- #
958
- private
959
- def rotation(mode=:NO_SPEC)
960
- synchronize do
961
- # if rotationing now by another process, return
962
- if @psync.locked? #=> if not process safe mode, will be return nil
963
- return false
964
- end
965
-
966
- # lock another process if enable
967
- @psync.lock
968
-
969
- do_rotate(mode)
970
-
971
- # unlock another process if enable
972
- @psync.unlock
973
- end
974
- end
975
-
976
- #
977
- # Rotate the log file now, and open a new one
978
- #
979
- private
980
- def do_rotate(mode)
981
- return nil if logf_not_usable
982
-
983
- # check already executed rotation?
984
- if mode != :FLUSH && !reached_limit?
985
- return false
986
- end
987
-
988
- # file age rotation
989
- if @rotate_by_term
990
- rtn = do_term_rotate
991
- return rtn
992
- end
993
-
994
- # file size rotation
995
- cnt = 1
996
- rotate_name = "#{@file_name}#{@rename_format}#{cnt}"
997
- rotate_name += ".gz" if @compress
998
-
999
- if File.exist?(rotate_name)
1000
- while File.exist?(rotate_name)
1001
- cnt += 1
1002
- rotate_name = "#{@file_name}#{@rename_format}#{cnt}"
1003
- rotate_name += ".gz" if @compress
1004
- end
1005
-
1006
- rename_wait_que = Array.new
1007
- for nc in 1...cnt
1008
- break if @rotation == 1
1009
- if (@compress)
1010
- rename_wait_que << "File.rename('#{@file_name}#{@rename_format}#{nc}.gz', '#{@file_name}#{@rename_format}#{nc+1}.gz')"
1011
- else
1012
- rename_wait_que << "File.rename('#{@file_name}#{@rename_format}#{nc}', '#{@file_name}#{@rename_format}#{nc+1}')"
1013
- end
1014
-
1015
- if @rotation
1016
- next if @rotation == 0
1017
- break if @rotation <= nc+1
1018
- end
1019
- end
1020
-
1021
- rename_wait_que.reverse!
1022
-
1023
- begin
1024
- rename_wait_que.each do |do_rename|
1025
- eval(do_rename)
1026
- end
1027
- rescue
1028
- SimpleRotate::Error.warning(SimpleRotate::Error::ROTATION_FAILED)
1029
- return false
1030
- end
1031
- end
1032
-
1033
- most_recent_name = "#{@file_name}#{@rename_format}1"
1034
- post_execute_rotate(most_recent_name)
1035
- end
1036
-
1037
- #
1038
- # Rotate the log file now, and open a new one
1039
- # for rotate by term
1040
- #
1041
- private
1042
- def do_term_rotate
1043
- date = Time.now.strftime(@term_format)
1044
- rotate_name = "#{@file_name}#{@rename_format}#{date}"
1045
-
1046
- # Don't rotation If a file with the same name already exists
1047
- return false if File.exists?(rotate_name)
1048
- return false if File.exists?("#{rotate_name}.gz")
1049
-
1050
- post_execute_rotate(rotate_name)
1051
- end
1052
-
1053
- #
1054
- # rename log_file & generate new one
1055
- #
1056
- private
1057
- def post_execute_rotate(after_name)
1058
- begin
1059
- @logf.close
1060
- File.rename(@file_name, after_name)
1061
- do_compress(after_name) if @compress
1062
- prepare_logf
1063
-
1064
- # sleep after rotation
1065
- sleep(@sleep_time) if @sleep_time > 0
1066
-
1067
- rescue
1068
- SimpleRotate::Error.warning(SimpleRotate::Error::ROTATION_FAILED)
1069
- reopen if file_closed?
1070
- end
1071
- end
1072
-
1073
- #
1074
- # compress rotated file
1075
- #
1076
- private
1077
- def do_compress(file)
1078
- contents = nil
1079
- File.open(file, File::RDONLY) do |f|
1080
- contents = f.read
1081
- end
1082
-
1083
- newf = "#{file}.gz"
1084
-
1085
- io = File.open(newf, File::WRONLY|File::CREAT|File::TRUNC)
1086
- Zlib::GzipWriter.wrap(io, @compress_level) do |writer|
1087
- writer.mtime = File.mtime(file).to_i
1088
- writer.orig_name = file
1089
- writer.write(contents)
1090
- end
1091
-
1092
- File.delete(file)
1093
- end
1094
-
1095
- #
1096
- # convert 'limit_size' to integer
1097
- # @param string|int $limit_size
1098
- # @return int
1099
- #
1100
- private
1101
- def trim_byte(limit)
1102
- return limit if limit.is_a?(Integer)
1103
-
1104
- kiro = "000"
1105
- mega = kiro + "000"
1106
- giga = mega + "000"
1107
- tera = giga + "000"
1108
- limit_size = limit
1109
-
1110
- if /K$/ =~ limit_size
1111
- limit_size = limit_size.sub(/K$/, "") + kiro
1112
- elsif /M$/ =~ limit_size
1113
- limit_size = limit_size.sub(/M$/, "") + mega
1114
- elsif /G$/ =~ limit_size
1115
- limit_size = limit_size.sub(/G$/, "") + giga
1116
- elsif /T$/ =~ limit_size
1117
- limit_size = limit_size.sub(/T$/, "") + tera
1118
- end
1119
-
1120
- return limit_size.to_i
1121
- end
1122
-
1123
- #--------------------
1124
- # method alias
1125
- #--------------------
1126
- alias_method :<<, :w
1127
- end
3
+ # Simple and safety logger
4
+ # @autor: Kazuya Hotta
5
+ #
6
+ require_relative "simple_rotate/core.rb"