blob: 73772ab814af8380e017991a7ce98f406181a33b [file]
/*
Copyright 2014 DataStax
Licensed 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 __CASS_LOGGER_HPP_INCLUDED__
#define __CASS_LOGGER_HPP_INCLUDED__
#include "cassandra.h"
#include "loop_thread.hpp"
#include "async_queue.hpp"
#include "mpmc_queue.hpp"
#include "config.hpp"
#include <stdarg.h>
#include <stdio.h>
#include <string>
namespace cass {
class Logger : public LoopThread {
public:
Logger(const Config& config)
: data_(config.log_data())
, cb_(config.log_callback())
, log_level_(config.log_level())
, log_queue_(config.queue_size_log()) {}
int init() { return log_queue_.init(loop(), this, on_log); }
void close_async() {
while (!log_queue_.enqueue(NULL)) {
// Keep trying
}
}
#define LOG_MESSAGE(severity) \
if (severity <= log_level_) { \
va_list args; \
va_start(args, format); \
log(severity, format, args); \
va_end(args); \
}
void critical(const char* format, ...) { LOG_MESSAGE(CASS_LOG_CRITICAL); }
void error(const char* format, ...) { LOG_MESSAGE(CASS_LOG_ERROR); }
void warn(const char* format, ...) { LOG_MESSAGE(CASS_LOG_WARN); }
void info(const char* format, ...) { LOG_MESSAGE(CASS_LOG_INFO); }
void debug(const char* format, ...) { LOG_MESSAGE(CASS_LOG_DEBUG); }
#undef LOG_MESSAGE
private:
struct LogMessage {
uint64_t time;
CassLogLevel severity;
std::string message;
};
void close() { log_queue_.close_handles(); }
std::string format_message(const char* format, va_list args) {
char buffer[1024];
int n = vsnprintf(buffer, sizeof(buffer), format, args);
return std::string(buffer, n);
}
void log(CassLogLevel severity, const char* format, va_list args) {
LogMessage* log_message = new LogMessage;
log_message->severity = severity;
log_message->message = format_message(format, args);
log_queue_.enqueue(log_message);
}
static void on_log(uv_async_t* async, int status) {
Logger* logger = static_cast<Logger*>(async->data);
bool is_closing = false;
LogMessage* log_message;
while (logger->log_queue_.dequeue(log_message)) {
if (log_message != NULL) {
if (log_message->severity != CASS_LOG_DISABLED) {
CassString message = cass_string_init2(log_message->message.data(),
log_message->message.size());
logger->cb_(logger->data_, log_message->time, log_message->severity,
message);
}
delete log_message;
} else {
is_closing = true;
}
}
if (is_closing) {
logger->close();
}
}
void* data_;
CassLogCallback cb_;
CassLogLevel log_level_;
AsyncQueue<MPMCQueue<LogMessage*> > log_queue_;
};
} // namespace cass
#endif