switch to new MPL based Fraunhofer FOKUS Public License
[senf.git] / senf / Utils / Logger / LogFormat.cc
1 // $Id$
2 //
3 // Copyright (C) 2009
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief LogFormat non-inline non-template implementation */
30
31 #include "LogFormat.hh"
32 //#include "LogFormat.ih"
33
34 // Custom includes
35 #include <unistd.h>
36 #include <locale>
37 #include <boost/date_time/posix_time/posix_time.hpp>
38 #include <senf/Scheduler/ClockService.hh>
39 #include <senf/Utils/Console/ScopedDirectory.hh>
40 #include <senf/Utils/Console/ParsedCommand.hh>
41
42 //#include "LogFormat.mpp"
43 #define prefix_
44 //-/////////////////////////////////////////////////////////////////////////////////////////////////
45
46 prefix_ senf::log::detail::LogFormat::LogFormat()
47     : tag_ (detail::getDefaultTag()), noformat_ (false), showTime_ (true),
48       showStream_ (false), showLevel_ (true), showArea_ (true), timeBase_ (-1)
49 {
50     timeFormat("%Y-%m-%d %H:%M:%S.%f-0000");
51 }
52
53 prefix_ senf::log::detail::LogFormat::LogFormat(console::ScopedDirectory<> & dir)
54     : tag_ (detail::getDefaultTag()), noformat_ (false), showTime_ (true),
55       showStream_ (false), showLevel_ (true), showArea_ (true), timeBase_ (-1)
56 {
57     namespace kw = console::kw;
58     namespace fty = console::factory;
59
60     timeFormat("%Y-%m-%d %H:%M:%S.%f-0000");
61
62     dir.add("showTime", fty::Command(&LogFormat::showTime, this)
63             .arg("flag","whether to display the time in log messages",
64                  kw::default_value = true)
65             .doc("Set time display in log messages. If time display is enabled, see the 'timeFormat'\n"
66                  "command to set the time format.") );
67     dir.add("showStream", fty::Command(&LogFormat::showStream, this)
68             .arg("flag","whether to display the stream in log messages",
69                  kw::default_value = true)
70             .doc("Set stream display in log messages.") );
71     dir.add("showLevel", fty::Command(&LogFormat::showLevel, this)
72             .arg("flag","whether to display the log level in log messages",
73                  kw::default_value = true)
74             .doc("Set log level display in log messages.") );
75     dir.add("showArea", fty::Command(&LogFormat::showArea, this)
76             .arg("flag","whether to display the area in log messages",
77                  kw::default_value = true)
78             .doc("Set area display in log messages.") );
79     dir.add("timeFormat", fty::Command(&LogFormat::timeFormat, this)
80             .arg("format","time format")
81             .doc("Set time format. The time format is specified using a format string. This format\n"
82                  "string follows the strftime format.\n"
83                  "\n"
84                  "As additional option, the format string may be set to the empty string. In this\n"
85                  "case the time will be displayed as 'second.nanosecond' value. IN this case, the\n"
86                  "time is displayed relative to the first message after changing the format.") );
87     dir.add("tag", fty::Command(&LogFormat::tag, this)
88             .arg("tag","log message tag prefix")
89             .doc("Every log message is optionally prefixed with a tag value. This value defaults to\n"
90                  "the executable name and pid.") );
91     dir.add("format", fty::Command(&LogFormat::consoleFormat, this)
92             .doc("Show the current log message format.") );
93 }
94
95 prefix_ void senf::log::detail::LogFormat::consoleFormat(std::ostream & os)
96 {
97     if (showTime_)                                           os << "showTime ";
98     if (showStream_)                                         os << "showStream ";
99     if (showLevel_)                                          os << "showLevel ";
100     if (showArea_)                                           os << "showArea ";
101     if (showTime_ || showStream_ || showLevel_ || showArea_) os << "\n";
102     else                                                     os << "(all flags disabled)\n";
103
104     os << "timeFormat \"" << timeFormat_ << "\"\n";
105     os << "tag \""        << tag_        << "\"\n";
106 }
107
108 prefix_ void senf::log::detail::LogFormat::timeFormat(std::string const & format)
109 {
110     timeFormat_ = format;
111     if (format.empty()) {
112         noformat_ = true;
113         timeBase_ = ClockService::now();
114     } else {
115         noformat_ = false;
116         std::locale const & loc (datestream_.getloc());
117         datestream_.imbue( std::locale(
118                                loc, new boost::posix_time::time_facet(format.c_str())) );
119     }
120 }
121
122 prefix_ std::string senf::log::detail::LogFormat::prefix(time_type timestamp,
123                                                          std::string const & stream,
124                                                          std::string const & area,
125                                                          unsigned level)
126 {
127     datestream_.str("");
128
129     if (showTime_) {
130         if (noformat_) {
131             time_type delta (timestamp - timeBase_);
132             datestream_ << std::setfill('0')  << std::right
133                         << std::setw(10) << (delta / 1000000000ll) << '.'
134                         << std::setw(9) << (delta % 1000000000ll);
135         }
136         else
137             datestream_ << senf::ClockService::abstime(timestamp);
138         datestream_ << ' ';
139     }
140     if (!tag_.empty())
141         datestream_ << tag_ << ": ";
142     if (showStream_)
143         datestream_ << '[' << stream << "] ";
144     if (showLevel_)
145         datestream_ << '[' << LEVELNAMES[level] << "] ";
146     if (showArea_ && area != "senf::log::DefaultArea")
147         datestream_ << '[' << area << "] ";
148
149     return datestream_.str();
150 }
151
152 //-/////////////////////////////////////////////////////////////////////////////////////////////////
153
154 prefix_ void senf::log::detail::quoteNonPrintable(std::string & s)
155 {
156     for (std::string::iterator i (s.begin()); i != s.end(); ++i)
157         if (*i < ' ' && *i != '\n')
158             *i = '?';
159 }
160
161 prefix_ std::string senf::log::detail::getDefaultTag()
162 {
163     std::stringstream ss;
164     ss << ::program_invocation_short_name << '[' << ::getpid() << ']';
165     return ss.str();
166 }
167
168 //-/////////////////////////////////////////////////////////////////////////////////////////////////
169 #undef prefix_
170 //#include "LogFormat.mpp"
171
172 \f
173 // Local Variables:
174 // mode: c++
175 // fill-column: 100
176 // comment-column: 40
177 // c-file-style: "senf"
178 // indent-tabs-mode: nil
179 // ispell-local-dictionary: "american"
180 // compile-command: "scons -u test"
181 // End: