FileChannel.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. //
  2. // FileChannel.cpp
  3. //
  4. // $Id: //poco/1.4/Foundation/src/FileChannel.cpp#3 $
  5. //
  6. // Library: Foundation
  7. // Package: Logging
  8. // Module: FileChannel
  9. //
  10. // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
  11. // and Contributors.
  12. //
  13. // SPDX-License-Identifier: BSL-1.0
  14. //
  15. #include "Poco/FileChannel.h"
  16. #include "Poco/ArchiveStrategy.h"
  17. #include "Poco/RotateStrategy.h"
  18. #include "Poco/PurgeStrategy.h"
  19. #include "Poco/Message.h"
  20. #include "Poco/NumberParser.h"
  21. #include "Poco/DateTimeFormatter.h"
  22. #include "Poco/DateTime.h"
  23. #include "Poco/LocalDateTime.h"
  24. #include "Poco/String.h"
  25. #include "Poco/Timespan.h"
  26. #include "Poco/Exception.h"
  27. #include "Poco/Ascii.h"
  28. namespace Poco {
  29. const std::string FileChannel::PROP_PATH = "path";
  30. const std::string FileChannel::PROP_ROTATION = "rotation";
  31. const std::string FileChannel::PROP_ARCHIVE = "archive";
  32. const std::string FileChannel::PROP_TIMES = "times";
  33. const std::string FileChannel::PROP_COMPRESS = "compress";
  34. const std::string FileChannel::PROP_PURGEAGE = "purgeAge";
  35. const std::string FileChannel::PROP_PURGECOUNT = "purgeCount";
  36. const std::string FileChannel::PROP_FLUSH = "flush";
  37. const std::string FileChannel::PROP_ROTATEONOPEN = "rotateOnOpen";
  38. FileChannel::FileChannel():
  39. _times("utc"),
  40. _compress(false),
  41. _flush(true),
  42. _rotateOnOpen(false),
  43. _pFile(0),
  44. _pRotateStrategy(0),
  45. _pArchiveStrategy(new ArchiveByNumberStrategy),
  46. _pPurgeStrategy(0)
  47. {
  48. }
  49. FileChannel::FileChannel(const std::string& path):
  50. _path(path),
  51. _times("utc"),
  52. _compress(false),
  53. _flush(true),
  54. _rotateOnOpen(false),
  55. _pFile(0),
  56. _pRotateStrategy(0),
  57. _pArchiveStrategy(new ArchiveByNumberStrategy),
  58. _pPurgeStrategy(0)
  59. {
  60. }
  61. FileChannel::~FileChannel()
  62. {
  63. try
  64. {
  65. close();
  66. delete _pRotateStrategy;
  67. delete _pArchiveStrategy;
  68. delete _pPurgeStrategy;
  69. }
  70. catch (...)
  71. {
  72. poco_unexpected();
  73. }
  74. }
  75. void FileChannel::open()
  76. {
  77. FastMutex::ScopedLock lock(_mutex);
  78. if (!_pFile)
  79. {
  80. _pFile = new LogFile(_path);
  81. if (_rotateOnOpen && _pFile->size() > 0)
  82. {
  83. try
  84. {
  85. _pFile = _pArchiveStrategy->archive(_pFile);
  86. purge();
  87. }
  88. catch (...)
  89. {
  90. _pFile = new LogFile(_path);
  91. }
  92. }
  93. }
  94. }
  95. void FileChannel::close()
  96. {
  97. FastMutex::ScopedLock lock(_mutex);
  98. delete _pFile;
  99. _pFile = 0;
  100. }
  101. void FileChannel::log(const Message& msg)
  102. {
  103. open();
  104. FastMutex::ScopedLock lock(_mutex);
  105. if (_pRotateStrategy && _pArchiveStrategy && _pRotateStrategy->mustRotate(_pFile))
  106. {
  107. try
  108. {
  109. _pFile = _pArchiveStrategy->archive(_pFile);
  110. purge();
  111. }
  112. catch (...)
  113. {
  114. _pFile = new LogFile(_path);
  115. }
  116. // we must call mustRotate() again to give the
  117. // RotateByIntervalStrategy a chance to write its timestamp
  118. // to the new file.
  119. _pRotateStrategy->mustRotate(_pFile);
  120. }
  121. _pFile->write(msg.getText(), _flush);
  122. }
  123. void FileChannel::setProperty(const std::string& name, const std::string& value)
  124. {
  125. FastMutex::ScopedLock lock(_mutex);
  126. if (name == PROP_TIMES)
  127. {
  128. _times = value;
  129. if (!_rotation.empty())
  130. setRotation(_rotation);
  131. if (!_archive.empty())
  132. setArchive(_archive);
  133. }
  134. else if (name == PROP_PATH)
  135. _path = value;
  136. else if (name == PROP_ROTATION)
  137. setRotation(value);
  138. else if (name == PROP_ARCHIVE)
  139. setArchive(value);
  140. else if (name == PROP_COMPRESS)
  141. setCompress(value);
  142. else if (name == PROP_PURGEAGE)
  143. setPurgeAge(value);
  144. else if (name == PROP_PURGECOUNT)
  145. setPurgeCount(value);
  146. else if (name == PROP_FLUSH)
  147. setFlush(value);
  148. else if (name == PROP_ROTATEONOPEN)
  149. setRotateOnOpen(value);
  150. else
  151. Channel::setProperty(name, value);
  152. }
  153. std::string FileChannel::getProperty(const std::string& name) const
  154. {
  155. if (name == PROP_TIMES)
  156. return _times;
  157. else if (name == PROP_PATH)
  158. return _path;
  159. else if (name == PROP_ROTATION)
  160. return _rotation;
  161. else if (name == PROP_ARCHIVE)
  162. return _archive;
  163. else if (name == PROP_COMPRESS)
  164. return std::string(_compress ? "true" : "false");
  165. else if (name == PROP_PURGEAGE)
  166. return _purgeAge;
  167. else if (name == PROP_PURGECOUNT)
  168. return _purgeCount;
  169. else if (name == PROP_FLUSH)
  170. return std::string(_flush ? "true" : "false");
  171. else if (name == PROP_ROTATEONOPEN)
  172. return std::string(_rotateOnOpen ? "true" : "false");
  173. else
  174. return Channel::getProperty(name);
  175. }
  176. Timestamp FileChannel::creationDate() const
  177. {
  178. if (_pFile)
  179. return _pFile->creationDate();
  180. else
  181. return 0;
  182. }
  183. UInt64 FileChannel::size() const
  184. {
  185. if (_pFile)
  186. return _pFile->size();
  187. else
  188. return 0;
  189. }
  190. const std::string& FileChannel::path() const
  191. {
  192. return _path;
  193. }
  194. void FileChannel::setRotation(const std::string& rotation)
  195. {
  196. std::string::const_iterator it = rotation.begin();
  197. std::string::const_iterator end = rotation.end();
  198. int n = 0;
  199. while (it != end && Ascii::isSpace(*it)) ++it;
  200. while (it != end && Ascii::isDigit(*it)) { n *= 10; n += *it++ - '0'; }
  201. while (it != end && Ascii::isSpace(*it)) ++it;
  202. std::string unit;
  203. while (it != end && Ascii::isAlpha(*it)) unit += *it++;
  204. RotateStrategy* pStrategy = 0;
  205. if ((rotation.find(',') != std::string::npos) || (rotation.find(':') != std::string::npos))
  206. {
  207. if (_times == "utc")
  208. pStrategy = new RotateAtTimeStrategy<DateTime>(rotation);
  209. else if (_times == "local")
  210. pStrategy = new RotateAtTimeStrategy<LocalDateTime>(rotation);
  211. else
  212. throw PropertyNotSupportedException("times", _times);
  213. }
  214. else if (unit == "daily")
  215. pStrategy = new RotateByIntervalStrategy(Timespan(1*Timespan::DAYS));
  216. else if (unit == "weekly")
  217. pStrategy = new RotateByIntervalStrategy(Timespan(7*Timespan::DAYS));
  218. else if (unit == "monthly")
  219. pStrategy = new RotateByIntervalStrategy(Timespan(30*Timespan::DAYS));
  220. else if (unit == "seconds") // for testing only
  221. pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::SECONDS));
  222. else if (unit == "minutes")
  223. pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::MINUTES));
  224. else if (unit == "hours")
  225. pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::HOURS));
  226. else if (unit == "days")
  227. pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::DAYS));
  228. else if (unit == "weeks")
  229. pStrategy = new RotateByIntervalStrategy(Timespan(n*7*Timespan::DAYS));
  230. else if (unit == "months")
  231. pStrategy = new RotateByIntervalStrategy(Timespan(n*30*Timespan::DAYS));
  232. else if (unit == "K")
  233. pStrategy = new RotateBySizeStrategy(n*1024);
  234. else if (unit == "M")
  235. pStrategy = new RotateBySizeStrategy(n*1024*1024);
  236. else if (unit.empty())
  237. pStrategy = new RotateBySizeStrategy(n);
  238. else if (unit != "never")
  239. throw InvalidArgumentException("rotation", rotation);
  240. delete _pRotateStrategy;
  241. _pRotateStrategy = pStrategy;
  242. _rotation = rotation;
  243. }
  244. void FileChannel::setArchive(const std::string& archive)
  245. {
  246. ArchiveStrategy* pStrategy = 0;
  247. if (archive == "number")
  248. {
  249. pStrategy = new ArchiveByNumberStrategy;
  250. }
  251. else if (archive == "timestamp")
  252. {
  253. if (_times == "utc")
  254. pStrategy = new ArchiveByTimestampStrategy<DateTime>;
  255. else if (_times == "local")
  256. pStrategy = new ArchiveByTimestampStrategy<LocalDateTime>;
  257. else
  258. throw PropertyNotSupportedException("times", _times);
  259. }
  260. else throw InvalidArgumentException("archive", archive);
  261. delete _pArchiveStrategy;
  262. pStrategy->compress(_compress);
  263. _pArchiveStrategy = pStrategy;
  264. _archive = archive;
  265. }
  266. void FileChannel::setCompress(const std::string& compress)
  267. {
  268. _compress = icompare(compress, "true") == 0;
  269. if (_pArchiveStrategy)
  270. _pArchiveStrategy->compress(_compress);
  271. }
  272. void FileChannel::setPurgeAge(const std::string& age)
  273. {
  274. delete _pPurgeStrategy;
  275. _pPurgeStrategy = 0;
  276. _purgeAge = "none";
  277. if (age.empty() || 0 == icompare(age, "none"))
  278. return;
  279. std::string::const_iterator it = age.begin();
  280. std::string::const_iterator end = age.end();
  281. int n = 0;
  282. while (it != end && Ascii::isSpace(*it)) ++it;
  283. while (it != end && Ascii::isDigit(*it)) { n *= 10; n += *it++ - '0'; }
  284. if (0 == n)
  285. throw InvalidArgumentException("Zero is not valid purge age.");
  286. while (it != end && Ascii::isSpace(*it)) ++it;
  287. std::string unit;
  288. while (it != end && Ascii::isAlpha(*it)) unit += *it++;
  289. Timespan::TimeDiff factor = Timespan::SECONDS;
  290. if (unit == "minutes")
  291. factor = Timespan::MINUTES;
  292. else if (unit == "hours")
  293. factor = Timespan::HOURS;
  294. else if (unit == "days")
  295. factor = Timespan::DAYS;
  296. else if (unit == "weeks")
  297. factor = 7*Timespan::DAYS;
  298. else if (unit == "months")
  299. factor = 30*Timespan::DAYS;
  300. else if (unit != "seconds")
  301. throw InvalidArgumentException("purgeAge", age);
  302. _pPurgeStrategy = new PurgeByAgeStrategy(Timespan(factor*n));
  303. _purgeAge = age;
  304. }
  305. void FileChannel::setPurgeCount(const std::string& count)
  306. {
  307. delete _pPurgeStrategy;
  308. _pPurgeStrategy = 0;
  309. _purgeAge = "none";
  310. if (count.empty() || 0 == icompare(count, "none"))
  311. return;
  312. std::string::const_iterator it = count.begin();
  313. std::string::const_iterator end = count.end();
  314. int n = 0;
  315. while (it != end && Ascii::isSpace(*it)) ++it;
  316. while (it != end && Ascii::isDigit(*it)) { n *= 10; n += *it++ - '0'; }
  317. if (0 == n)
  318. throw InvalidArgumentException("Zero is not valid purge count.");
  319. while (it != end && Ascii::isSpace(*it)) ++it;
  320. delete _pPurgeStrategy;
  321. _pPurgeStrategy = new PurgeByCountStrategy(n);
  322. _purgeCount = count;
  323. }
  324. void FileChannel::setFlush(const std::string& flush)
  325. {
  326. _flush = icompare(flush, "true") == 0;
  327. }
  328. void FileChannel::setRotateOnOpen(const std::string& rotateOnOpen)
  329. {
  330. _rotateOnOpen = icompare(rotateOnOpen, "true") == 0;
  331. }
  332. void FileChannel::purge()
  333. {
  334. if (_pPurgeStrategy)
  335. {
  336. try
  337. {
  338. _pPurgeStrategy->purge(_path);
  339. }
  340. catch (...)
  341. {
  342. }
  343. }
  344. }
  345. } // namespace Poco