| 115 | }; |
| 116 | |
| 117 | class LOG : public Logger<LOG> { |
| 118 | public: |
| 119 | static void File(const std::string& name, const char* openMode = "w") { |
| 120 | const std::string& file = Name(name); |
| 121 | if (file == "stdout") { |
| 122 | LOG::File() = stdout; |
| 123 | } else if (file == "stderr") { |
| 124 | LOG::File() = stderr; |
| 125 | } else { |
| 126 | LOG::File() = fopen(file.c_str(), openMode); |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | static void Limit(off_t size) { |
| 131 | LOG::Limit() = size; |
| 132 | } |
| 133 | |
| 134 | private: |
| 135 | static std::string& Name(const std::string& name) { |
| 136 | static std::string file_name = "stdout"; |
| 137 | if (!name.empty()) |
| 138 | file_name.assign(name); |
| 139 | return file_name; |
| 140 | } |
| 141 | |
| 142 | static FILE*& File() { |
| 143 | static FILE* file = stdout; |
| 144 | return file; |
| 145 | } |
| 146 | |
| 147 | static off_t& Limit() { |
| 148 | static off_t size_limit = 0; |
| 149 | return size_limit; |
| 150 | } |
| 151 | |
| 152 | static void Log(const std::string& str, bool fatal) { |
| 153 | if (fatal) Limit() = 0; |
| 154 | |
| 155 | FILE* output = File(); |
| 156 | if (output) { |
| 157 | fwrite(str.data(), sizeof(char), str.size(), output); |
| 158 | fflush(output); |
| 159 | |
| 160 | if (Limit() && !isatty(fileno(output))) { |
| 161 | if (lseek(fileno(output), 0, SEEK_END) > Limit()) { |
| 162 | fclose(output), File(""); |
| 163 | } |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | if (fatal && !isatty(fileno(output))) { |
| 168 | fputs(str.c_str(), stderr); |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | friend class Logger<LOG>; |
| 173 | }; |
| 174 |
no test coverage detected