fixed right padding issue for several output members
[senf.git] / senf / Utils / Logger / LogFormat.cc
1 // $Id$
2 //
3 // Copyright (C) 2009
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief LogFormat non-inline non-template implementation */
25
26 #include "LogFormat.hh"
27 //#include "LogFormat.ih"
28
29 // Custom includes
30 #include <errno.h>
31 #include <unistd.h>
32 #include <locale>
33 #include <boost/date_time/posix_time/posix_time.hpp>
34 #include <senf/Scheduler/ClockService.hh>
35 #include <senf/Utils/Console/ScopedDirectory.hh>
36 #include <senf/Utils/Console/ParsedCommand.hh>
37
38 //#include "LogFormat.mpp"
39 #define prefix_
40 //-/////////////////////////////////////////////////////////////////////////////////////////////////
41
42 prefix_ senf::log::detail::LogFormat::LogFormat()
43     : tag_ (detail::getDefaultTag()), noformat_ (false), showTime_ (true),
44       showStream_ (false), showLevel_ (true), showArea_ (true), timeBase_ (-1)
45 {
46     timeFormat("%Y-%m-%d %H:%M:%S.%f-0000");
47 }
48
49 prefix_ senf::log::detail::LogFormat::LogFormat(console::ScopedDirectory<> & dir)
50     : tag_ (detail::getDefaultTag()), noformat_ (false), showTime_ (true),
51       showStream_ (false), showLevel_ (true), showArea_ (true), timeBase_ (-1)
52 {
53     namespace kw = console::kw;
54     namespace fty = console::factory;
55
56     timeFormat("%Y-%m-%d %H:%M:%S.%f-0000");
57
58     dir.add("showTime", fty::Command(&LogFormat::showTime, this)
59             .arg("flag","whether to display the time in log messages",
60                  kw::default_value = true)
61             .doc("Set time display in log messages. If time display is enabled, see the 'timeFormat'\n"
62                  "command to set the time format.") );
63     dir.add("showStream", fty::Command(&LogFormat::showStream, this)
64             .arg("flag","whether to display the stream in log messages",
65                  kw::default_value = true)
66             .doc("Set strean display in log messages.") );
67     dir.add("showLevel", fty::Command(&LogFormat::showLevel, this)
68             .arg("flag","whether to display the log level in log messages",
69                  kw::default_value = true)
70             .doc("Set log level display in log messages.") );
71     dir.add("showArea", fty::Command(&LogFormat::showArea, this)
72             .arg("flag","whether to display the area in log messages",
73                  kw::default_value = true)
74             .doc("Set area display in log messages.") );
75     dir.add("timeFormat", fty::Command(&LogFormat::timeFormat, this)
76             .arg("format","time format")
77             .doc("Set time format. The time format is specified using a format string. This format\n"
78                  "string follows the strftime format.\n"
79                  "\n"
80                  "As additional option, the format string may be set to the empty string. In this\n"
81                  "case the time will be displayed as 'second.nanosecond' value. IN this case, the\n"
82                  "time is displayed relative to the first message after changing the format.") );
83     dir.add("tag", fty::Command(&LogFormat::tag, this)
84             .arg("tag","log message tag prefix")
85             .doc("Every log message is optionally prefixed with a tag value. This value defaults to\n"
86                  "the executable name and pid.") );
87     dir.add("format", fty::Command(&LogFormat::consoleFormat, this)
88             .doc("Show the current log message format.") );
89 }
90
91 prefix_ void senf::log::detail::LogFormat::consoleFormat(std::ostream & os)
92 {
93     if (showTime_)                                           os << "showTime ";
94     if (showStream_)                                         os << "showStream ";
95     if (showLevel_)                                          os << "showLevel ";
96     if (showArea_)                                           os << "showArea ";
97     if (showTime_ || showStream_ || showLevel_ || showArea_) os << "\n";
98     else                                                     os << "(all flags disabled)\n";
99
100     os << "timeFormat \"" << timeFormat_ << "\"\n";
101     os << "tag \""        << tag_        << "\"\n";
102 }
103
104 prefix_ void senf::log::detail::LogFormat::timeFormat(std::string const & format)
105 {
106     timeFormat_ = format;
107     if (format.empty()) {
108         noformat_ = true;
109         timeBase_ = -1;
110     } else {
111         noformat_ = false;
112         std::locale const & loc (datestream_.getloc());
113         datestream_.imbue( std::locale(
114                                loc, new boost::posix_time::time_facet(format.c_str())) );
115     }
116 }
117
118 prefix_ std::string senf::log::detail::LogFormat::prefix(time_type timestamp,
119                                                          std::string const & stream,
120                                                          std::string const & area,
121                                                          unsigned level)
122 {
123     datestream_.str("");
124
125     if (showTime_) {
126         if (noformat_) {
127             if (timeBase_ == -1) timeBase_ = timestamp;
128             time_type delta (timestamp - timeBase_);
129             datestream_ << std::setfill('0')  << std::right
130                         << std::setw(10) << (delta / 1000000000ll) << '.'
131                         << std::setw(9) << (delta % 1000000000ll);
132         }
133         else
134             datestream_ << senf::ClockService::abstime(timestamp);
135         datestream_ << ' ';
136     }
137     if (!tag_.empty())
138         datestream_ << tag_ << ": ";
139     if (showStream_)
140         datestream_ << '[' << stream << "] ";
141     if (showLevel_)
142         datestream_ << '[' << LEVELNAMES[level] << "] ";
143     if (showArea_ && area != "senf::log::DefaultArea")
144         datestream_ << '[' << area << "] ";
145
146     return datestream_.str();
147 }
148
149 //-/////////////////////////////////////////////////////////////////////////////////////////////////
150
151 prefix_ void senf::log::detail::quoteNonPrintable(std::string & s)
152 {
153     for (std::string::iterator i (s.begin()); i != s.end(); ++i)
154         if (*i < ' ' && *i != '\n')
155             *i = '?';
156 }
157
158 prefix_ std::string senf::log::detail::getDefaultTag()
159 {
160     std::stringstream ss;
161     ss << ::program_invocation_short_name << '[' << ::getpid() << ']';
162     return ss.str();
163 }
164
165 //-/////////////////////////////////////////////////////////////////////////////////////////////////
166 #undef prefix_
167 //#include "LogFormat.mpp"
168
169 \f
170 // Local Variables:
171 // mode: c++
172 // fill-column: 100
173 // comment-column: 40
174 // c-file-style: "senf"
175 // indent-tabs-mode: nil
176 // ispell-local-dictionary: "american"
177 // compile-command: "scons -u test"
178 // End: