| /* |
| Licensed to the Software Freedom Conservancy (SFC) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The SFC licenses this file |
| to you under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #ifndef logging_h |
| #define logging_h |
| |
| #ifdef _WIN32 |
| #pragma warning(push) |
| #pragma warning(disable:4996 4717) |
| #define fileno _fileno |
| #define isatty _isatty |
| #define lseek _lseek |
| #ifdef _ftime |
| #define ftime _ftime |
| #endif |
| #endif |
| |
| #ifdef unix |
| #include <sys/types.h> |
| #include <unistd.h> |
| #else |
| #include <io.h> |
| #include <comdef.h> |
| #endif |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/timeb.h> |
| #include <time.h> |
| #include <sstream> |
| #include <string> |
| #include <iostream> |
| |
| template <class _LOGGER> class Logger { |
| public: |
| Logger() : fatal_(false) {} |
| |
| enum LogLevel { |
| logFATAL = 0, logERROR, logWARN, logINFO, logDEBUG, logTRACE }; |
| |
| ~Logger() { |
| os_ << std::endl, _LOGGER::Log(os_.str(), fatal_); |
| if (fatal_) { |
| exit(EXIT_FAILURE); |
| } |
| } |
| |
| static void Level(const std::string& level) { |
| Level() = ToLogLevel(level); |
| } |
| |
| static LogLevel& Level() { |
| static LogLevel level = GetLogLevelEnv(); |
| return level; |
| } |
| |
| std::ostringstream& Stream(LogLevel level) { |
| static char severity[] = { 'F', 'E', 'W', 'I', 'D', 'T' }; |
| os_ << severity[level] << ' ' << Time(); |
| if (level == logFATAL) |
| fatal_ = true, os_ << L"FATAL "; |
| return os_; |
| } |
| |
| static std::string Time() { |
| struct timeb tb; ftime(&tb); |
| |
| char time[26]; |
| size_t length = strftime(time, sizeof(time), "%Y-%m-%d %H:%M:%S:", |
| localtime(reinterpret_cast<const time_t*>(&tb.time))); |
| sprintf(time + length, "%03u ", tb.millitm); |
| |
| return time; |
| } |
| |
| private: |
| |
| static LogLevel ToLogLevel(const std::string& level) { |
| if (level == "ERROR") { |
| return logERROR; |
| } else if (level == "WARN" ) { |
| return logWARN; |
| } else if (level == "INFO" ) { |
| return logINFO; |
| } else if (level == "DEBUG") { |
| return logDEBUG; |
| } else if (level == "TRACE") { |
| return logTRACE; |
| } else { |
| return logFATAL; |
| } |
| } |
| |
| static LogLevel GetLogLevelEnv() { |
| char* tmp = getenv("SELENIUM_LOG_LEVEL"); |
| return tmp ? ToLogLevel(std::string(tmp)) : logFATAL; |
| } |
| |
| std::ostringstream os_; |
| bool fatal_; |
| }; |
| |
| class LOG : public Logger<LOG> { |
| public: |
| static void File(const std::string& name, const char* openMode = "w") { |
| const std::string& file = Name(name); |
| if (file == "stdout") { |
| LOG::File() = stdout; |
| } else if (file == "stderr") { |
| LOG::File() = stderr; |
| } else { |
| LOG::File() = fopen(file.c_str(), openMode); |
| } |
| } |
| |
| static void Limit(off_t size) { |
| LOG::Limit() = size; |
| } |
| |
| private: |
| static std::string& Name(const std::string& name) { |
| static std::string file_name = "stdout"; |
| if (!name.empty()) |
| file_name.assign(name); |
| return file_name; |
| } |
| |
| static FILE*& File() { |
| static FILE* file = stdout; |
| return file; |
| } |
| |
| static off_t& Limit() { |
| static off_t size_limit = 0; |
| return size_limit; |
| } |
| |
| static void Log(const std::string& str, bool fatal) { |
| if (fatal) Limit() = 0; |
| |
| FILE* output = File(); |
| if (output) { |
| fwrite(str.data(), sizeof(char), str.size(), output); |
| fflush(output); |
| |
| if (Limit() && !isatty(fileno(output))) { |
| if (lseek(fileno(output), 0, SEEK_END) > Limit()) { |
| fclose(output), File(""); |
| } |
| } |
| } |
| |
| if (fatal && !isatty(fileno(output))) { |
| fputs(str.c_str(), stderr); |
| } |
| } |
| |
| friend class Logger<LOG>; |
| }; |
| |
| #ifdef _WIN32 |
| #pragma warning(pop) |
| #endif |
| |
| |
| #define LOG(LEVEL) \ |
| if (LOG::log ## LEVEL > LOG::Level()) ; \ |
| else LOG().Stream(LOG::log ## LEVEL) << __FILE__ << "(" << __LINE__ << ") " /* << stuff here */ |
| |
| #ifdef _WIN32 |
| #define LOGHR(LEVEL,HR) LOG( ## LEVEL) << HR << " [" << (_bstr_t(_com_error((DWORD) HR).ErrorMessage())) << "]: " |
| #define LOGERR(LEVEL) LOG( ## LEVEL) << " [Windows Error " << (::GetLastError()) << "]: " |
| #define LOGWSTRING(STR) _bstr_t( (## STR).c_str()) |
| #endif |
| |
| |
| #endif // logging_h |