FileLogOutput.cpp
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // This file is part of FZIs ic_workspace.
5 //
6 // This program is free software licensed under the LGPL
7 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
8 // You can find a copy of this license in LICENSE folder in the top
9 // directory of the source code.
10 //
11 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
12 //
13 // -- END LICENSE BLOCK ------------------------------------------------
14 
15 //----------------------------------------------------------------------
22 //----------------------------------------------------------------------
24 
25 #include <boost/filesystem/path.hpp>
26 #include <boost/filesystem/operations.hpp>
27 #include <iostream>
28 
29 #include "icl_core/os_fs.h"
30 #include "icl_core_config/Config.h"
32 
33 #if defined(_SYSTEM_POSIX_) && !defined(__ANDROID__)
34 # include <wordexp.h>
35 #endif
36 
37 namespace icl_core {
38 namespace logging {
39 
41 
42 LogOutputStream *FileLogOutput::create(const icl_core::String& name, const icl_core::String& config_prefix,
43  icl_core::logging::LogLevel log_level)
44 {
45  return new FileLogOutput(name, config_prefix, log_level);
46 }
47 
50  : LogOutputStream(name, config_prefix, log_level),
51  m_rotate(false),
52  m_last_rotation(0),
53  m_delete_old_files(false),
54  m_delete_older_than_days(0)
55 #if defined(_IC_BUILDER_ZLIB_)
56  , m_zipped_log_file(NULL)
57 #endif
58 {
59  icl_core::config::get<bool>(config_prefix + "/Rotate", m_rotate);
60  if (m_rotate)
61  {
63  }
64 
65  if (icl_core::config::get<uint32_t>(config_prefix + "/DeleteOlderThan", m_delete_older_than_days))
66  {
67  m_delete_old_files = true;
68  }
69 
70 #if defined(_IC_BUILDER_ZLIB_)
71  m_online_zip = icl_core::config::getDefault<bool>(config_prefix + "/Zip", false);
72 #endif
73 
74  m_flush = icl_core::config::getDefault<bool>(config_prefix + "/Flush", true);
75 
76  if (icl_core::config::get<icl_core::String>(config_prefix + "/FileName", m_filename))
77  {
79 
80  // Determine the last write time of the log file, if it already
81  // exists.
82  boost::filesystem::path log_file_path(m_filename);
83  if (boost::filesystem::exists(log_file_path))
84  {
85  if (boost::filesystem::is_directory(log_file_path))
86  {
87  std::cerr << "The filename specified for log output stream "
88  << config_prefix << " is a directory." << std::endl;
89  }
90  else
91  {
92  m_last_rotation = icl_core::TimeStamp(boost::filesystem::last_write_time(log_file_path)).days();
93  rotateLogFile();
94  }
95  }
96 
97  openLogFile();
98  }
99  else
100  {
101  std::cerr << "No filename specified for file log output stream " << config_prefix << std::endl;
102  }
103 }
104 
106  icl_core::logging::LogLevel log_level, bool flush)
107  : LogOutputStream(name, log_level),
108  m_filename(filename),
109  m_rotate(false),
110  m_last_rotation(0),
111  m_delete_old_files(false),
113  m_flush(flush)
114 #if defined(_IC_BUILDER_ZLIB_)
115  , m_online_zip(false),
116  m_zipped_log_file(NULL)
117 #endif
118 {
119  expandFilename();
120  openLogFile();
121 }
122 
124 {
125  closeLogFile();
126 }
127 
129 {
130  rotateLogFile();
131 
132  if (!isOpen())
133  {
134  openLogFile();
135  }
136 
137  if (isOpen())
138  {
139 #ifdef _IC_BUILDER_ZLIB_
140  if (m_online_zip)
141  {
142  gzwrite(m_zipped_log_file, log_line.c_str(), static_cast<unsigned int>(log_line.length()));
143  }
144  else
145 #endif
146  {
147  m_log_file << log_line;
148  }
149 
150  if (m_flush)
151  {
152  flush();
153  }
154  }
155 }
156 
158 {
159 #ifdef _IC_BUILDER_ZLIB_
160  if (m_online_zip)
161  {
162  return m_zipped_log_file != NULL;
163  }
164  else
165 #endif
166  {
167  return m_log_file.is_open();
168  }
169 }
170 
172 {
173 #ifdef _IC_BUILDER_ZLIB_
174  if (m_online_zip)
175  {
176  gzflush(m_zipped_log_file, Z_SYNC_FLUSH);
177  }
178  else
179 #endif
180  {
181  m_log_file.flush();
182  }
183 }
184 
186 {
187 #ifdef _IC_BUILDER_ZLIB_
188  if (m_online_zip)
189  {
190  if (m_zipped_log_file != NULL)
191  {
192  gzclose(m_zipped_log_file);
193  m_zipped_log_file = NULL;
194  }
195  }
196  else
197 #endif
198  {
199  if (m_log_file.is_open())
200  {
201  m_log_file.close();
202  }
203  }
204 }
205 
207 {
208 #if defined(_IC_BUILDER_ZLIB_)
209  if (m_online_zip)
210  {
211  m_zipped_log_file = gzopen(m_filename.c_str(), "a+b");
212  if (m_zipped_log_file == NULL)
213  {
214  std::cerr << "Could not open log file " << m_filename << std::endl;
215  }
216  else
217  {
218  const char *buffer = "\n\n-------------FILE (RE-)OPENED------------------\n";
219  gzwrite(m_zipped_log_file, buffer, static_cast<unsigned int>(strlen(buffer)));
220  }
221  }
222  else
223 #endif
224  if (!m_log_file.is_open())
225  {
226  m_log_file.open(m_filename.c_str(), std::ios::out | std::ios::app);
227  if (m_log_file.is_open())
228  {
229  m_log_file << "\n\n-------------FILE (RE-)OPENED------------------\n";
230  m_log_file.flush();
231  }
232  else
233  {
234  std::cerr << "Could not open log file " << m_filename << std::endl;
235  }
236  }
237 }
238 
240 {
241  if (m_rotate)
242  {
243  int64_t current_day = icl_core::TimeStamp::now().days();
244  if (m_last_rotation != current_day)
245  {
246  // First, close the log file if it's open.
247  closeLogFile();
248 
249  // Move the file. ZIP it, if libz is available.
250  char time_str[12];
251  icl_core::TimeStamp(24*3600*m_last_rotation).strfTime(time_str, 12, ".%Y-%m-%d");
252 #ifdef _IC_BUILDER_ZLIB_
253  if (!m_online_zip)
254  {
255  icl_core::os::zipFile(m_filename.c_str(), time_str);
257  }
258  else
259 #endif
260  {
261  icl_core::os::rename(m_filename.c_str(), (m_filename + time_str).c_str());
262  }
263 
264  // Delete old log files.
265  if (m_delete_old_files)
266  {
267 #if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2
268  boost::filesystem::path log_file_path = boost::filesystem::path(m_filename).branch_path();
269  std::string log_file_name = boost::filesystem::path(m_filename).leaf();
270 #else
271  boost::filesystem::path log_file_path = boost::filesystem::path(m_filename).parent_path();
272  std::string log_file_name = boost::filesystem::path(m_filename).filename().string();
273 #endif
274  if (boost::filesystem::exists(log_file_path) && boost::filesystem::is_directory(log_file_path))
275  {
276  icl_core::TimeStamp delete_older_than(24*3600*(current_day - m_delete_older_than_days));
277  for (boost::filesystem::directory_iterator it(log_file_path), end; it != end; ++it)
278  {
279  // If the found file starts with the name of the log file the check its last write time.
280  if (!is_directory(*it)
281  && icl_core::TimeStamp(boost::filesystem::last_write_time(*it)) < delete_older_than
282 #if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2
283  && it->leaf().find(log_file_name) == 0
284 #else
285  && it->path().filename().string().find(log_file_name) == 0
286 #endif
287  )
288  {
289  boost::filesystem::remove(*it);
290  }
291  }
292  }
293  }
294 
295  // Store the rotation time.
296  m_last_rotation = current_day;
297 
298  // Re-open the log file.
299  openLogFile();
300  }
301  }
302 }
303 
305 {
306  // Expand environment variables.
307 #if defined(_SYSTEM_POSIX_) && !defined(__ANDROID__)
308  wordexp_t p;
309  if (wordexp(m_filename.c_str(), &p, 0) == 0)
310  {
311  if (p.we_wordc > 0)
312  {
313  m_filename = p.we_wordv[0];
314  }
315  }
316  //wordfree(&p);
317 #elif defined(_SYSTEM_WIN32_)
318  // TODO: Implement this with ExpandEnvironmenStrings()
319 #endif
320 }
321 
322 }
323 }
static LogOutputStream * create(const icl_core::String &name, const icl_core::String &config_prefix, icl_core::logging::LogLevel log_level=cDEFAULT_LOG_LEVEL)
Represents absolute times.
Definition: TimeStamp.h:61
static TimeStamp now()
Definition: TimeStamp.cpp:111
int64_t days() const
Use this function if you want to express the time in days.
Definition: TimeBase.h:107
virtual void pushImpl(const icl_core::String &log_line)
Base header file for the configuration framework.
Defines logging macros.
signed __int64 int64_t
Definition: msvc_stdint.h:102
#define REGISTER_LOG_OUTPUT_STREAM(name, factory)
bool get< bool >(const icl_core::String &key, bool &value)
Template specialization for boolean values.
Definition: Config.h:122
int unlink(const char *filename)
Definition: os_fs.h:52
ThreadStream & endl(ThreadStream &stream)
Definition: ThreadStream.h:249
int rename(const char *old_filename, const char *new_filename)
Definition: os_fs.h:47
void strfTime(char *dest, size_t max_len, const char *format) const
Definition: TimeStamp.cpp:203
static char buffer[2000]
Contains global filesystem related functions, encapsulated into the icl_core::os namespace.
This is an output stream class for log messages.
std::string String
Definition: BaseTypes.h:43
Contains icl_logging::FileLogOutput.
FileLogOutput(const icl_core::String &name, const icl_core::String &config_prefix, icl_core::logging::LogLevel log_level)
icl_core::String name() const


fzi_icl_core
Author(s):
autogenerated on Mon Jun 10 2019 13:17:58