25 #include <boost/format.hpp>
26 #include <boost/range/adaptor/reversed.hpp>
40 defineOptionalProperty<int>(
"MaxLogFileCount",
42 "Number of log files to keep before starting to delete old "
43 "files. If zero, no file will be deleted.");
44 defineOptionalProperty<std::string>(
45 "LogFileName",
"ArmarXLog",
"Logfilename without ending");
46 defineOptionalProperty<std::string>(
"LogFileEnding",
"log",
"Logfilename ending");
47 defineOptionalProperty<std::string>(
50 "If set, log will be stored in this path. If not set, log will be stored "
51 "in $ARMARX_USER_CONFIG_DIR/log/ (or $HOME/.armarx/log/ if $ARMARX_USER_CONFIG_DIR is "
53 defineOptionalProperty<std::string>(
"LogTopicName",
"Log",
"Name of the topic to be used");
54 defineOptionalProperty<bool>(
55 "SplitByApplication",
true,
"Create additional log files for each application");
61 std::string directoryStr;
62 if (getProperty<std::string>(
"LogDir").isSet())
64 directoryStr = getProperty<std::string>(
"LogDir").getValue();
67 else if (
const char* workspace = std::getenv(
"ARMARX_USER_CONFIG_DIR"))
69 directoryStr = (std::filesystem::path(workspace) /
"log").
string();
73 directoryStr = std::string(
"$HOME/.armarx/log/");
79 if (!std::filesystem::exists(directory))
81 ARMARX_INFO <<
"Log path not found - creating it: " << directory.string();
82 std::error_code errcode;
83 std::filesystem::create_directories(directory, errcode);
86 ARMARX_ERROR <<
"Creating directories failed: " << errcode.message();
91 auto ending = getProperty<std::string>(
"LogFileEnding").getValue();
92 auto fileBasename = getProperty<std::string>(
"LogFileName").getValue();
94 directoryStr, getProperty<int>(
"MaxLogFileCount").getValue(), fileBasename, ending);
97 if (getProperty<bool>(
"SplitByApplication").getValue())
99 auto filePath = std::filesystem::path(
filename);
100 directory /= filePath.stem();
101 if (!std::filesystem::exists(directory))
103 ARMARX_INFO <<
"Log path not found - creating it: " << directory;
104 std::error_code errcode;
105 std::filesystem::create_directories(directory, errcode);
108 ARMARX_ERROR <<
"Creating directories failed: " << errcode.message();
113 directory.string() +
"/" + filePath.stem().string() +
"-%1%." + ending;
117 auto logfilePath = std::filesystem::path(directoryStr) / std::filesystem::path(
filename);
118 fileStream.open(logfilePath.string().c_str(), std::ofstream::out);
121 ARMARX_ERROR <<
"Failed to open " << logfilePath.string();
124 ARMARX_INFO <<
"Logging to " << logfilePath.string();
125 fileStream <<
"Log starting at " << IceUtil::Time::now().toDateTime() <<
", "
126 <<
"with log name " <<
filename <<
"\n";
127 usingTopic(getProperty<std::string>(
"LogTopicName").getValue());
138 std::unique_lock lock(
mutex);
156 std::vector<std::string>
159 std::vector<std::string> result;
160 namespace fs = std::filesystem;
161 fs::path someDir(dir);
162 fs::directory_iterator end_iter;
164 using result_set_t = std::multimap<std::filesystem::file_time_type, fs::path>;
165 result_set_t result_set;
167 if (fs::exists(someDir) && fs::is_directory(someDir))
169 for (fs::directory_iterator dir_iter(someDir); dir_iter != end_iter; ++dir_iter)
171 if (fs::is_regular_file(dir_iter->status()))
174 result_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter));
180 result.push_back(elem.second.string());
188 const std::string& fileBasename,
189 const std::string& fileNameEnding)
const
193 std::string connectorString =
"-";
194 const boost::regex e(fileBasename + connectorString +
"([0-9]+)\\.");
196 int highestNumber = 0;
197 for (
auto file :
files)
199 boost::match_results<std::string::const_iterator> what;
200 file = std::filesystem::path(file).filename().string();
202 bool found_match = boost::regex_search(file, what, e);
205 for (
size_t i = 1; i < what.size(); i += 2)
207 std::string numberStr = what[i];
208 int number = atoi(numberStr.c_str());
209 highestNumber =
std::max(number, highestNumber);
211 auto filenameCandidate = fileBasename + connectorString +
213 if (std::filesystem::exists(dir +
"/" + filenameCandidate))
216 if (trials >= maxLogFileCount && maxLogFileCount > 0)
219 std::filesystem::remove(dir +
"/" + filenameCandidate);
227 return fileBasename + connectorString +
ValueToString(highestNumber) +
"." + fileNameEnding;
233 return "ArmarXFileLogger";
241 if (!msg.tag.empty())
243 catStr =
"[" + msg.tag +
"]: ";
250 std::unique_lock lock(mutex);
251 if (!fileStream.is_open())
256 std::string logLevel;
259 case armarx::MessageType::eUNDEFINED:
260 logLevel =
"UNDEFINED";
262 case armarx::MessageType::eDEBUG:
265 case armarx::MessageType::eVERBOSE:
266 logLevel =
"VERBOSE";
268 case armarx::MessageType::eINFO:
271 case armarx::MessageType::eIMPORTANT:
272 logLevel =
"IMPORTANT";
274 case armarx::MessageType::eWARN:
277 case armarx::MessageType::eERROR:
280 case armarx::MessageType::eFATAL:
283 case armarx::MessageType::eLogLevelCount:
284 logLevel =
"LogLevelCount";
288 std::stringstream newLines;
289 newLines <<
"[" + time.toDateTime().substr(time.toDateTime().find(
' ') + 1) +
"]" +
"[" +
290 msg.who +
"]" + catStr +
"[" + logLevel +
"]";
291 newLines << msg.what <<
"\n";
292 fileStream << newLines.str();
293 if (getProperty<bool>(
"SplitByApplication").getValue())
295 auto it = applicationFileStreams.find(msg.who);
296 if (it == applicationFileStreams.end())
298 auto filepath = boost::format(applicationsLogFileBasePath) % msg.who;
299 it = applicationFileStreams
301 std::shared_ptr<std::ofstream>(
302 new std::ofstream(filepath.str().c_str())))
305 if (!it->second->is_open())
307 ARMARX_WARNING <<
"Failed to open for logging: " << filepath.str();
312 *(it->second) << newLines.str();