1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
#!/usr/bin/env ruby -w
# encoding: UTF-8
#
# = Log.rb -- The TaskJuggler III Project Management Software
#
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
# by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
require 'singleton'
require 'monitor'
require 'term/ansicolor'
class TaskJuggler
# The Log class implements a filter for segmented execution traces. The
# trace messages are filtered based on their segment name and the nesting
# level of the segments. The class is a Singleton, so there is only one
# instance in the program.
class Log < Monitor
include Singleton
@@level = 0
@@stack = []
@@segments = []
@@silent = true
@@progress = 0
@@progressMeter = ''
# Set the maximum nesting level that should be shown. Segments with a
# nesting level greater than _l_ will be silently dropped.
def Log.level=(l)
@@level = l
end
# The trace output can be limited to a list of segments. Messages not in
# these segments will be ignored. Messages from segments that are nested
# into the shown segments will be shown for the next @@level nested
# segments.
def Log.segments=(s)
@@segments = s
end
# if +s+ is true, progress information will not be shown.
def Log.silent=(s)
@@silent = s
end
# Return the @@silent value.
def Log.silent
@@silent
end
# This function is used to open a new segment. +segment+ is the name of
# the segment and +message+ is a description of it.
def Log.enter(segment, message)
return if @@level == 0
@@stack << segment
Log.msg { ">> [#{segment}] #{message}" }
end
# This function is used to close an open segment. To make this mechanism a
# bit more robust, it will search the stack of open segments for a segment
# with that name and will close all nested segments as well.
def Log.exit(segment, message = nil)
return if @@level == 0
Log.msg { "<< [#{segment}] #{message}" } if message
if @@stack.include?(segment)
loop do
m = @@stack.pop
break if m == segment
end
end
end
# Use this function to show a log message within the currently active
# segment. The message is the result of the passed block. The block will
# only be evaluated if the message will actually be shown.
def Log.msg(&block)
return if @@level == 0
offset = 0
unless @@segments.empty?
showMessage = false
@@stack.each do |segment|
# If a segment list is used to filter the output, we look for the
# first listed segments on the stack. This and all nested segments
# will be shown.
if @@segments.include?(segment)
offset = @@stack.index(segment)
showMessage = true
break
end
end
return unless showMessage
end
if @@stack.length - offset < @@level
$stderr.puts ' ' * (@@stack.length - offset) + yield(block)
end
end
# Print out a status message unless we are in silent mode.
def Log.status(message)
return if @@silent
$stdout.puts message
end
# The progress meter can be a textual progress bar or some animated
# character sequence that informs the user about ongoing activities. Call
# this function to start the progress meter display or to change the info
# +text+. The the meter is active the text cursor is always returned to
# the start of the same line. Consequent output will overwrite the last
# meter text.
def Log.startProgressMeter(text)
return if @@silent
maxlen = 60
text = text.ljust(maxlen)
text = text[0..maxlen - 1] if text.length_utf8 > maxlen
@@progressMeter = text
$stdout.print("#{@@progressMeter} ...\r")
end
# This sets the progress meter status to "done" and puts the cursor into
# the next line again.
def Log.stopProgressMeter
return if @@silent
$stdout.print("#{@@progressMeter} [ " +
Term::ANSIColor.green("Done") + " ]\n")
end
# This function may only be called when Log#startProgressMeter has been
# called before. It updates the progress indicator to the next symbol to
# visualize ongoing activity.
def Log.activity
return if @@silent
indicator = %w( - \\ | / )
@@progress = (@@progress.to_i + 1) % indicator.length
$stdout.print("#{@@progressMeter} [#{indicator[@@progress]}]\r")
end
# This function may only be called when Log#startProgressMeter has been
# called before. It updates the progress bar to the given +percent+
# completion value. The value should be between 0.0 and 1.0.
def Log.progress(percent)
return if @@silent
percent = 0.0 if percent < 0.0
percent = 1.0 if percent > 1.0
@@progress = percent
length = 16
full = (length * percent).to_i
bar = '=' * full + ' ' * (length - full)
label = (percent * 100.0).to_i.to_s + '%'
bar[length / 2 - label.length / 2, label.length] = label
$stdout.print("#{@@progressMeter} [" +
Term::ANSIColor.green("#{bar}") + "]\r")
end
end
end
|