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