| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF 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. |
| */ |
| |
| #include "logger.hpp" |
| #include "integration.hpp" |
| |
| #include "cassandra.h" |
| #include "scoped_lock.hpp" |
| |
| #include <ctime> |
| #include <iomanip> |
| #include <iostream> |
| #include <sstream> |
| |
| using namespace datastax::internal; |
| using namespace test::driver; |
| |
| #define LOGGER_DIRECTORY "log" |
| #ifdef _WIN32 |
| #define FILE_MODE 0 |
| #define LOCALTIME(tm, time) localtime_s(tm, time) |
| #else |
| #define FILE_MODE S_IRWXU | S_IRWXG | S_IROTH |
| #define LOCALTIME(tm, time) localtime_r(time, tm) |
| #endif |
| |
| Logger::Logger() |
| : count_(0) {} |
| |
| Logger::~Logger() { |
| if (output_.is_open()) { |
| output_.close(); |
| } |
| } |
| |
| void Logger::initialize(const std::string& test_case, const std::string& test_name) { |
| // Create the logger directory |
| std::string path = std::string(LOGGER_DIRECTORY) + Utils::PATH_SEPARATOR + test_case; |
| path = Utils::replace_all(path, "_", std::string(1, Utils::PATH_SEPARATOR)); |
| std::vector<std::string> path_tokens = Utils::explode(path, Utils::PATH_SEPARATOR); |
| std::string mkdir_path; |
| for (std::vector<std::string>::const_iterator iterator = path_tokens.begin(); |
| iterator < path_tokens.end(); ++iterator) { |
| mkdir_path += *iterator + Utils::PATH_SEPARATOR; |
| Utils::mkdir(mkdir_path); |
| } |
| |
| // Create the relative file name for the test and the associated stream |
| std::string filename = path + Utils::PATH_SEPARATOR + test_name + ".log"; |
| output_.open(filename.c_str(), std::fstream::out | std::fstream::trunc); |
| |
| // Initialize the driver logger callback |
| if (output_.fail()) { |
| TEST_LOG_ERROR("Unable to Create Log File: " << filename); |
| } |
| |
| // Create the mutex for callback operations (thread safety) |
| uv_mutex_init(&mutex_); |
| |
| // Set the maximum driver log level to capture all logs messages |
| cass_log_set_level(CASS_LOG_TRACE); |
| cass_log_set_callback(Logger::log, this); |
| } |
| |
| void Logger::add_critera(const std::string& criteria) { |
| ScopedMutex lock(&mutex_); |
| search_criteria_.push_back(criteria); |
| } |
| |
| void test::driver::Logger::clear_critera() { |
| ScopedMutex lock(&mutex_); |
| search_criteria_.clear(); |
| } |
| |
| size_t Logger::count() { return count_; } |
| |
| void Logger::log(const CassLogMessage* log, void* data) { |
| Logger* logger = static_cast<Logger*>(data); |
| ScopedMutex lock(&(logger->mutex_)); |
| |
| // Get the log message |
| std::string message = log->message; |
| |
| // Convert the epoch to human readable format date/time |
| cass_uint64_t epoch_seconds = log->time_ms / 1000; |
| unsigned short milliseconds = log->time_ms % 1000; |
| time_t rawtime = static_cast<time_t>(epoch_seconds); |
| struct tm date_time; |
| LOCALTIME(&date_time, &rawtime); |
| |
| // Create the date formatted output |
| std::stringstream date; |
| int month = (date_time.tm_mon + 1); |
| date << date_time.tm_year + 1900 << "/" << (month < 10 ? "0" : "") << month << "/" |
| << (date_time.tm_mday < 10 ? "0" : "") << date_time.tm_mday; |
| |
| // Create the formatted time |
| std::stringstream time; |
| time << (date_time.tm_hour < 10 ? "0" : "") << date_time.tm_hour << ":" |
| << (date_time.tm_min < 10 ? "0" : "") << date_time.tm_min << ":" |
| << (date_time.tm_sec < 10 ? "0" : "") << date_time.tm_sec << "." << std::setfill('0') |
| << std::setw(3) << milliseconds; |
| |
| // Create the formatted log message and output to the file |
| std::string severity = cass_log_level_string(log->severity); |
| logger->output_ << date.str() << " " << time.str() << " " << severity << ": " << message << " (" |
| << log->file << ":" << log->line << ") " << std::endl; |
| |
| // Determine if the log message matches any of the criteria |
| for (std::vector<std::string>::const_iterator iterator = logger->search_criteria_.begin(); |
| iterator != logger->search_criteria_.end(); ++iterator) { |
| if (message.find(*iterator) != std::string::npos) { |
| ++logger->count_; |
| } |
| } |
| } |
| |
| void test::driver::Logger::reset() { |
| ScopedMutex lock(&mutex_); |
| search_criteria_.clear(); |
| count_ = 0; |
| } |
| |
| void test::driver::Logger::reset_count() { |
| ScopedMutex lock(&mutex_); |
| count_ = 0; |
| } |