00001 #ifndef toast_log_rotation_policies_hpp_INCLUDED
00002 #define toast_log_rotation_policies_hpp_INCLUDED
00003
00004 #include <iostream>
00005 #include <boost/lexical_cast.hpp>
00006 #include <boost/filesystem.hpp>
00007 #include <toast/concept_check.hpp>
00008 #include <toast/contracts.hpp>
00009
00010 #include <cstdio>
00011
00021 namespace toast {
00022 namespace log {
00023
00024 namespace size {
00025 const unsigned int KB = 1024;
00026 const unsigned int MB = KB * KB;
00027 const unsigned int GB = KB * KB * KB;
00028 const unsigned int TB = KB * KB * KB * KB;
00029 }
00030
00041 template <typename Policy>
00042 struct RotationCheckPolicyConcept
00043 {
00044 void constraints() {
00045 bool a = p.test(100);
00046 Policy_Sub p_sub;
00047 }
00048
00049 private:
00050 class Policy_Sub : public Policy
00051 {
00052 public:
00053 Policy_Sub()
00054 {
00055 const char f[10] = "blah";
00056 Policy::test(f);
00057 Policy::reset();
00058 }
00059 };
00060 Policy p;
00061 };
00062
00067 struct never_rotate {
00068 static bool test(unsigned int) { return (false); }
00069 protected:
00070 static bool test(const char*) { return (false); }
00071 static void reset() { return; }
00072 ~never_rotate() {}
00073 };
00074
00094 struct message_limit {
00095 message_limit() : max_messages_(0), messages_(0) {}
00096 void max_messages(unsigned int messages) { max_messages_ = messages; }
00097 bool test(unsigned int)
00098 {
00099 ++messages_;
00100
00101 if (max_messages_ && messages_ >= max_messages_) {
00102 messages_ = 0;
00103 return (true);
00104 }
00105
00106 return (false);
00107 }
00108 protected:
00109 static bool test(const char*) { return (false); }
00110 void reset() { messages_ = 0; }
00111 unsigned int max_messages_;
00112 unsigned int messages_;
00113 ~message_limit() {}
00114 };
00115
00127 struct max_file_size {
00128 max_file_size() : max_size_(0), aggregate_(0) {}
00129 void max_size(unsigned int size) { max_size_ = size; }
00130 bool test(unsigned int size)
00131 {
00132 aggregate_ += size;
00133
00134 if (max_size_ && aggregate_ >= max_size_) {
00135 aggregate_ = 0;
00136 return (true);
00137 }
00138
00139 return (false);
00140 }
00141
00142 protected:
00143 bool test(const char* f)
00144 {
00145 FILE* pf = 0;
00146 pf = std::fopen(f, "rb");
00147
00148 if (!pf) return (false);
00149
00150 std::fseek(pf, 0, SEEK_END);
00151 long size = std::ftell(pf);
00152 std::fclose(pf);
00153
00154 return (test(size));
00155 }
00156 void reset() { aggregate_ = 0; }
00157 unsigned int max_size_;
00158 unsigned int aggregate_;
00159 ~max_file_size() {}
00160 };
00161
00167 template <typename Policy>
00168 struct RotationImplPolicyConcept
00169 {
00170 void constraints() {
00171 Policy_Sub p;
00172 }
00173 private:
00174 class Policy_Sub : public Policy
00175 {
00176 public:
00177 Policy_Sub()
00178 {
00179 const char f[10] = "blah";
00180 Policy::rotate(f);
00181 }
00182 };
00183 };
00184
00204 struct roll_rotation
00205 {
00206 roll_rotation() : max_rotated_(2) {}
00207 void max_rotated(unsigned int logs)
00208 {
00209 TOAST_IN(logs >= 2);
00210 max_rotated_ = logs;
00211 }
00212 protected:
00213 const char* rotate(const char* f)
00214 {
00215 using boost::lexical_cast;
00216 using boost::filesystem::exists;
00217 using boost::filesystem::remove;
00218
00219 std::string basename(f);
00220
00221 unsigned int test_suffix = max_rotated_ - 1;
00222 unsigned int top_suffix = max_rotated_ - 1;
00223 unsigned int bottom_suffix = 0;
00224 unsigned int range = 0;
00225
00230 if (exists(basename + "." + lexical_cast<std::string>(bottom_suffix))) {
00231
00232 for (;;) {
00233
00239 if (exists(basename + "." + lexical_cast<std::string>(test_suffix))) {
00240
00241 if (test_suffix == max_rotated_ - 1) break;
00242 if (test_suffix == top_suffix - 1) break;
00243
00244 bottom_suffix = test_suffix;
00245 range = top_suffix - bottom_suffix;
00246 test_suffix += (range / 2) + (range % 2);
00247
00248 } else {
00249
00250 if (test_suffix == bottom_suffix + 1) {
00251 test_suffix = bottom_suffix;
00252 break;
00253 }
00254
00255 top_suffix = test_suffix;
00256 range = top_suffix - bottom_suffix;
00257 test_suffix -= (range / 2) + (range % 2);
00258
00259 }
00260
00261 }
00262
00263 test_suffix += (test_suffix == max_rotated_ - 1 ? 0 : 1);
00264 for (unsigned int log = test_suffix; log > 0; --log) {
00265 rename((basename + "." + lexical_cast<std::string>(log - 1)).c_str(),
00266 (basename + "." + lexical_cast<std::string>(log)).c_str());
00267 }
00268
00269 }
00270
00271 rename(basename.c_str(), (basename + ".0").c_str());
00272 return (f);
00273 }
00274
00275 unsigned int max_rotated_;
00276 ~roll_rotation() {}
00277 };
00278
00285 template <typename Policy>
00286 struct RotationPolicyConcept
00287 {
00288 void constraints() {
00289 const char f[10] = "blah";
00290 bool a = p.test(100);
00291 Policy_Sub psub;
00292 }
00293 private:
00294 class Policy_Sub : public Policy
00295 {
00296 public:
00297 Policy_Sub()
00298 {
00299 const char f[10] = "test";
00300 Policy::rotate();
00301 Policy::set_file(f);
00302 }
00303 };
00304 Policy p;
00305 };
00306
00307 template <typename RotationCheckPolicy, typename RotationImplPolicy>
00308 struct rotation_policy :
00309 public RotationCheckPolicy,
00310 public RotationImplPolicy
00311 {
00312 TOAST_CLASS_REQUIRE(RotationCheckPolicy, toast::log, RotationCheckPolicyConcept);
00313 TOAST_CLASS_REQUIRE(RotationImplPolicy, toast::log, RotationImplPolicyConcept);
00314
00315 protected:
00316 const char* rotate()
00317 {
00318 base_filename_ = RotationImplPolicy::rotate(base_filename_.c_str());
00319 RotationCheckPolicy::reset();
00320 return (base_filename_.c_str());
00321 }
00322 void set_file(const char* f)
00323 {
00324 base_filename_ = f;
00325
00326 if (RotationCheckPolicy::test(f))
00327 RotationImplPolicy::rotate(f);
00328 }
00329
00330 std::string base_filename_;
00331 ~rotation_policy() {}
00332 };
00333
00336 }
00337 }
00338
00339 #endif // toast_log_rotation_policies_hpp_INCLUDED