25#include <boost/format.hpp>
26#include <boost/range/adaptor/reversed.hpp>
42 "Number of log files to keep before starting to delete old "
43 "files. If zero, no file will be deleted.");
45 "LogFileName",
"ArmarXLog",
"Logfilename without ending");
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 "
55 "SplitByApplication",
true,
"Create additional log files for each application");
61 std::string directoryStr;
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();
94 directoryStr,
getProperty<int>(
"MaxLogFileCount").getValue(), fileBasename, ending);
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";
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));
178 for (
auto& elem : boost::adaptors::reverse(result_set))
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 +
"]: ";
249 IceUtil::Time time = IceUtil::Time::microSeconds(msg.time);
250 std::unique_lock lock(
mutex);
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";
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();
static bool ReplaceEnvVars(std::string &string)
ReplaceEnvVars replaces environment variables in a string with their values, if the env.
ArmarXFileLoggerPropertyDefinitions(std::string prefix)
std::string applicationsLogFileBasePath
void onInitComponent() override
Pure virtual hook for the subclass.
std::vector< std::string > getDirListOrderedByDate(const std::string &dir) const
void onDisconnectComponent() override
Hook for subclass.
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Creates the property definition container.
void onConnectComponent() override
Pure virtual hook for the subclass.
void writeLog(const LogMessage &, const Ice::Current &) override
std::map< std::string, std::shared_ptr< std::ofstream > > applicationFileStreams
std::string getNextLogFileNameAndDeleteOldFiles(const std::string &dir, int maxLogFileCount, const std::string &fileBasename, const std::string &fileNameEnding) const
void onExitComponent() override
Hook for subclass.
std::string getDefaultName() const override
Retrieve default name of component.
ComponentPropertyDefinitions(std::string prefix, bool hasObjectNameParameter=true)
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Property< PropertyType > getProperty(const std::string &name)
static std::string CropFunctionName(const std::string &originalFunctionName)
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
PropertyDefinition< PropertyType > & defineOptionalProperty(const std::string &name, PropertyType defaultValue, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
#define ARMARX_INFO
The normal logging level.
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
This file offers overloads of toIce() and fromIce() functions for STL container types.
fs::path remove_trailing_separator(fs::path p)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::string ValueToString(const T &value)