NAWA  0.8
Web Application Framework for C++
Log.cpp
Go to the documentation of this file.
1 
6 /*
7  * Copyright (C) 2019-2021 Tobias Flaig.
8  *
9  * This file is part of nawa.
10  *
11  * nawa is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License,
13  * version 3, as published by the Free Software Foundation.
14  *
15  * nawa is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with nawa. If not, see <https://www.gnu.org/licenses/>.
22  */
23 
24 #include <atomic>
25 #include <iomanip>
26 #include <mutex>
27 #include <nawa/Exception.h>
28 #include <nawa/oss.h>
29 #include <nawa/logging/Log.h>
30 
31 using namespace nawa;
32 using namespace std;
33 
34 namespace {
35  struct DestructionDetector {
36  bool destructed = false;
37 
38  ~DestructionDetector() { destructed = true; }
39  } destructionDetector;
40 
41  bool locked = false;
42  ostream* out;
43  ofstream logFile;
45  bool extendedFormat = false;
46  unique_ptr<string> hostnameStr;
47  pid_t pid = 0;
48  atomic_uint instanceCount(0);
49  mutex outLock;
50 }// namespace
51 
52 struct Log::Data {
53  std::string appname;
54  Level defaultLevel;
56  explicit Data(Level defaultLevel = Level::INFORMATIONAL) : defaultLevel(defaultLevel) {}
57 };
58 
59 Log::Log() noexcept {
60  data = make_unique<Data>(Level::INFORMATIONAL);
61 
62  if (instanceCount == 0) {
63  out = &cerr;
64 
65  // get hostname
66  hostnameStr = make_unique<string>(oss::getSystemHostname());
67 
68  // get pid
69  pid = getpid();
70  }
71 
72  // appname is nawa by default
73  data->appname = "nawa";
74 
75  ++instanceCount;
76 }
77 
78 Log::Log(string appname, Level level) noexcept : Log() {
79  data->appname = move(appname);
80  data->defaultLevel = level;
81 }
82 
83 Log::Log(Level level) noexcept : Log() {
84  data->defaultLevel = level;
85 }
86 
87 Log::Log(Log const& other) noexcept {
88  data = make_unique<Data>(*other.data);
89  ++instanceCount;
90 }
91 
92 Log& Log::operator=(Log const& other) noexcept {
93  if (this != &other) {
94  *data = *other.data;
95  ++instanceCount;
96  }
97  return *this;
98 }
99 
101  if (!destructionDetector.destructed) {
102  --instanceCount;
103  if (instanceCount == 0) {
104  if (logFile.is_open()) {
105  logFile.close();
106  }
107  locked = false;
108  }
109  } else {
110  if (logFile.is_open()) {
111  logFile.close();
112  }
113  }
114 }
115 
116 void Log::setStream(ostream* os) noexcept {
117  if (!locked) {
118  out = os;
119  }
120 }
121 
122 void Log::setOutfile(string const& filename) {
123  if (!locked) {
124  if (logFile.is_open()) {
125  logFile.close();
126  }
127  logFile.open(filename, ofstream::out | ofstream::app);
128  if (!logFile) {
129  throw Exception(__PRETTY_FUNCTION__, 1,
130  "Failed to open requested file for writing.");
131  }
132  out = &logFile;
133  }
134 }
135 
137  if (!locked) {
138  outputLevel = level;
139  }
140 }
141 
142 void Log::setExtendedFormat(bool useExtendedFormat) {
143  if (!locked) {
144  extendedFormat = useExtendedFormat;
145  }
146 }
147 
148 void Log::lockStream() noexcept {
149  locked = true;
150 }
151 
152 bool Log::isLocked() noexcept {
153  return locked;
154 }
155 
156 void Log::setAppname(string appname) noexcept {
157  data->appname = move(appname);
158 }
159 
160 void Log::setDefaultLogLevel(Level level) noexcept {
161  data->defaultLevel = level;
162 }
163 
164 void Log::write(string const& msg) {
165  write(msg, data->defaultLevel);
166 }
167 
168 void Log::write(string const& msg, Level level) {
169  if (level <= outputLevel && outputLevel != Level::OFF && level != Level::OFF) {
170  auto now = time(nullptr);
171  lock_guard<mutex> l(outLock);
172  if (extendedFormat) {
173  *out << put_time(localtime(&now), "%b %d %H:%M:%S ") << *hostnameStr << ' '
174  << oss::getProgramInvocationName() << '[' << pid << "]: ";
175  }
176  cerr << "[" << data->appname << "] " << msg << endl;
177  out->flush();
178  }
179 }
180 
181 void Log::operator()(string const& msg) {
182  write(msg, data->defaultLevel);
183 }
184 
185 void Log::operator()(string const& msg, Level level) {
186  write(msg, level);
187 }
Exception class that can be used by apps to catch errors resulting from nawa function calls.
Simple class for (not (yet) thread-safe) logging to stderr or to any other output stream.
Definition: Log.h:38
Log & operator=(Log const &other) noexcept
Definition: Log.cpp:92
virtual ~Log()
Definition: Log.cpp:100
static void setOutputLevel(Level level)
Definition: Log.cpp:136
void operator()(std::string const &msg)
Definition: Log.cpp:181
static void setOutfile(std::string const &filename)
Definition: Log.cpp:122
Level
Definition: Log.h:47
void setDefaultLogLevel(Level level) noexcept
Definition: Log.cpp:160
Log() noexcept
Definition: Log.cpp:59
static void lockStream() noexcept
Definition: Log.cpp:148
void write(std::string const &msg)
Definition: Log.cpp:164
void setAppname(std::string appname) noexcept
Definition: Log.cpp:156
static bool isLocked() noexcept
Definition: Log.cpp:152
static void setStream(std::ostream *os) noexcept
Definition: Log.cpp:116
static void setExtendedFormat(bool useExtendedFormat)
Definition: Log.cpp:142
std::string getProgramInvocationName()
Definition: oss.h:52
std::string getSystemHostname()
Definition: oss.h:42
Definition: AppInit.h:31
This file contains helpers for operating-system specific stuff.