00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00022
00023 #include "icl_core_logging/FileLogOutput.h"
00024
00025 #include <boost/filesystem/path.hpp>
00026 #include <boost/filesystem/operations.hpp>
00027 #include <iostream>
00028
00029 #include "icl_core/os_fs.h"
00030 #include "icl_core_config/Config.h"
00031 #include "icl_core_logging/Logging.h"
00032
00033 #if defined(_SYSTEM_POSIX_) && !defined(__ANDROID__)
00034 # include <wordexp.h>
00035 #endif
00036
00037 namespace icl_core {
00038 namespace logging {
00039
00040 REGISTER_LOG_OUTPUT_STREAM(File, &FileLogOutput::create)
00041
00042 LogOutputStream *FileLogOutput::create(const icl_core::String& name, const icl_core::String& config_prefix,
00043 icl_core::logging::LogLevel log_level)
00044 {
00045 return new FileLogOutput(name, config_prefix, log_level);
00046 }
00047
00048 FileLogOutput::FileLogOutput(const icl_core::String& name, const icl_core::String& config_prefix,
00049 icl_core::logging::LogLevel log_level)
00050 : LogOutputStream(name, config_prefix, log_level),
00051 m_rotate(false),
00052 m_last_rotation(0),
00053 m_delete_old_files(false),
00054 m_delete_older_than_days(0)
00055 #if defined(_IC_BUILDER_ZLIB_)
00056 , m_zipped_log_file(NULL)
00057 #endif
00058 {
00059 icl_core::config::get<bool>(config_prefix + "/Rotate", m_rotate);
00060 if (m_rotate)
00061 {
00062 m_last_rotation = icl_core::TimeStamp::now().days();
00063 }
00064
00065 if (icl_core::config::get<uint32_t>(config_prefix + "/DeleteOlderThan", m_delete_older_than_days))
00066 {
00067 m_delete_old_files = true;
00068 }
00069
00070 #if defined(_IC_BUILDER_ZLIB_)
00071 m_online_zip = icl_core::config::getDefault<bool>(config_prefix + "/Zip", false);
00072 #endif
00073
00074 m_flush = icl_core::config::getDefault<bool>(config_prefix + "/Flush", true);
00075
00076 if (icl_core::config::get<icl_core::String>(config_prefix + "/FileName", m_filename))
00077 {
00078 expandFilename();
00079
00080
00081
00082 boost::filesystem::path log_file_path(m_filename);
00083 if (boost::filesystem::exists(log_file_path))
00084 {
00085 if (boost::filesystem::is_directory(log_file_path))
00086 {
00087 std::cerr << "The filename specified for log output stream "
00088 << config_prefix << " is a directory." << std::endl;
00089 }
00090 else
00091 {
00092 m_last_rotation = icl_core::TimeStamp(boost::filesystem::last_write_time(log_file_path)).days();
00093 rotateLogFile();
00094 }
00095 }
00096
00097 openLogFile();
00098 }
00099 else
00100 {
00101 std::cerr << "No filename specified for file log output stream " << config_prefix << std::endl;
00102 }
00103 }
00104
00105 FileLogOutput::FileLogOutput(const icl_core::String& name, const icl_core::String& filename,
00106 icl_core::logging::LogLevel log_level, bool flush)
00107 : LogOutputStream(name, log_level),
00108 m_filename(filename),
00109 m_rotate(false),
00110 m_last_rotation(0),
00111 m_delete_old_files(false),
00112 m_delete_older_than_days(0),
00113 m_flush(flush)
00114 #if defined(_IC_BUILDER_ZLIB_)
00115 , m_online_zip(false),
00116 m_zipped_log_file(NULL)
00117 #endif
00118 {
00119 expandFilename();
00120 openLogFile();
00121 }
00122
00123 FileLogOutput::~FileLogOutput()
00124 {
00125 closeLogFile();
00126 }
00127
00128 void FileLogOutput::pushImpl(const icl_core::String& log_line)
00129 {
00130 rotateLogFile();
00131
00132 if (!isOpen())
00133 {
00134 openLogFile();
00135 }
00136
00137 if (isOpen())
00138 {
00139 #ifdef _IC_BUILDER_ZLIB_
00140 if (m_online_zip)
00141 {
00142 gzwrite(m_zipped_log_file, log_line.c_str(), static_cast<unsigned int>(log_line.length()));
00143 }
00144 else
00145 #endif
00146 {
00147 m_log_file << log_line;
00148 }
00149
00150 if (m_flush)
00151 {
00152 flush();
00153 }
00154 }
00155 }
00156
00157 bool FileLogOutput::isOpen()
00158 {
00159 #ifdef _IC_BUILDER_ZLIB_
00160 if (m_online_zip)
00161 {
00162 return m_zipped_log_file != NULL;
00163 }
00164 else
00165 #endif
00166 {
00167 return m_log_file.is_open();
00168 }
00169 }
00170
00171 void FileLogOutput::flush()
00172 {
00173 #ifdef _IC_BUILDER_ZLIB_
00174 if (m_online_zip)
00175 {
00176 gzflush(m_zipped_log_file, Z_SYNC_FLUSH);
00177 }
00178 else
00179 #endif
00180 {
00181 m_log_file.flush();
00182 }
00183 }
00184
00185 void FileLogOutput::closeLogFile()
00186 {
00187 #ifdef _IC_BUILDER_ZLIB_
00188 if (m_online_zip)
00189 {
00190 if (m_zipped_log_file != NULL)
00191 {
00192 gzclose(m_zipped_log_file);
00193 m_zipped_log_file = NULL;
00194 }
00195 }
00196 else
00197 #endif
00198 {
00199 if (m_log_file.is_open())
00200 {
00201 m_log_file.close();
00202 }
00203 }
00204 }
00205
00206 void FileLogOutput::openLogFile()
00207 {
00208 #if defined(_IC_BUILDER_ZLIB_)
00209 if (m_online_zip)
00210 {
00211 m_zipped_log_file = gzopen(m_filename.c_str(), "a+b");
00212 if (m_zipped_log_file == NULL)
00213 {
00214 std::cerr << "Could not open log file " << m_filename << std::endl;
00215 }
00216 else
00217 {
00218 const char *buffer = "\n\n-------------FILE (RE-)OPENED------------------\n";
00219 gzwrite(m_zipped_log_file, buffer, static_cast<unsigned int>(strlen(buffer)));
00220 }
00221 }
00222 else
00223 #endif
00224 if (!m_log_file.is_open())
00225 {
00226 m_log_file.open(m_filename.c_str(), std::ios::out | std::ios::app);
00227 if (m_log_file.is_open())
00228 {
00229 m_log_file << "\n\n-------------FILE (RE-)OPENED------------------\n";
00230 m_log_file.flush();
00231 }
00232 else
00233 {
00234 std::cerr << "Could not open log file " << m_filename << std::endl;
00235 }
00236 }
00237 }
00238
00239 void FileLogOutput::rotateLogFile()
00240 {
00241 if (m_rotate)
00242 {
00243 int64_t current_day = icl_core::TimeStamp::now().days();
00244 if (m_last_rotation != current_day)
00245 {
00246
00247 closeLogFile();
00248
00249
00250 char time_str[12];
00251 icl_core::TimeStamp(24*3600*m_last_rotation).strfTime(time_str, 12, ".%Y-%m-%d");
00252 #ifdef _IC_BUILDER_ZLIB_
00253 if (!m_online_zip)
00254 {
00255 icl_core::os::zipFile(m_filename.c_str(), time_str);
00256 icl_core::os::unlink(m_filename.c_str());
00257 }
00258 else
00259 #endif
00260 {
00261 icl_core::os::rename(m_filename.c_str(), (m_filename + time_str).c_str());
00262 }
00263
00264
00265 if (m_delete_old_files)
00266 {
00267 #if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2
00268 boost::filesystem::path log_file_path = boost::filesystem::path(m_filename).branch_path();
00269 std::string log_file_name = boost::filesystem::path(m_filename).leaf();
00270 #else
00271 boost::filesystem::path log_file_path = boost::filesystem::path(m_filename).parent_path();
00272 std::string log_file_name = boost::filesystem::path(m_filename).filename().string();
00273 #endif
00274 if (boost::filesystem::exists(log_file_path) && boost::filesystem::is_directory(log_file_path))
00275 {
00276 icl_core::TimeStamp delete_older_than(24*3600*(current_day - m_delete_older_than_days));
00277 for (boost::filesystem::directory_iterator it(log_file_path), end; it != end; ++it)
00278 {
00279
00280 if (!is_directory(*it)
00281 && icl_core::TimeStamp(boost::filesystem::last_write_time(*it)) < delete_older_than
00282 #if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2
00283 && it->leaf().find(log_file_name) == 0
00284 #else
00285 && it->path().filename().string().find(log_file_name) == 0
00286 #endif
00287 )
00288 {
00289 boost::filesystem::remove(*it);
00290 }
00291 }
00292 }
00293 }
00294
00295
00296 m_last_rotation = current_day;
00297
00298
00299 openLogFile();
00300 }
00301 }
00302 }
00303
00304 void FileLogOutput::expandFilename()
00305 {
00306
00307 #if defined(_SYSTEM_POSIX_) && !defined(__ANDROID__)
00308 wordexp_t p;
00309 if (wordexp(m_filename.c_str(), &p, 0) == 0)
00310 {
00311 if (p.we_wordc > 0)
00312 {
00313 m_filename = p.we_wordv[0];
00314 }
00315 }
00316
00317 #elif defined(_SYSTEM_WIN32_)
00318
00319 #endif
00320 }
00321
00322 }
00323 }