Home | History | Annotate | Download | only in src
      1 // Copyright 2009 Google Inc. All Rights Reserved.
      2 
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "logger.h"
     16 
     17 #include <pthread.h>
     18 #include <stdarg.h>
     19 #include <stdio.h>
     20 #include <unistd.h>
     21 
     22 #include <string>
     23 #include <vector>
     24 
     25 // This file must work with autoconf on its public version,
     26 // so these includes are correct.
     27 #include "sattypes.h"
     28 
     29 
     30 Logger *Logger::GlobalLogger() {
     31   static Logger logger;
     32   return &logger;
     33 }
     34 
     35 void Logger::VLogF(int priority, const char *format, va_list args) {
     36   if (priority > verbosity_) {
     37     return;
     38   }
     39   char buffer[4096];
     40   int length = vsnprintf(buffer, sizeof buffer, format, args);
     41   if (static_cast<size_t>(length) >= sizeof buffer) {
     42     length = sizeof buffer;
     43     buffer[sizeof buffer - 1] = '\n';
     44   }
     45   QueueLogLine(new string(buffer, length));
     46 }
     47 
     48 void Logger::StartThread() {
     49   LOGGER_ASSERT(!thread_running_);
     50   thread_running_ = true;
     51   LOGGER_ASSERT(0 == pthread_create(&thread_, NULL, &StartRoutine, this));
     52 }
     53 
     54 void Logger::StopThread() {
     55   LOGGER_ASSERT(thread_running_);
     56   thread_running_ = false;
     57   LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_));
     58   bool need_cond_signal = queued_lines_.empty();
     59   queued_lines_.push_back(NULL);
     60   LOGGER_ASSERT(0 == pthread_mutex_unlock(&queued_lines_mutex_));
     61   if (need_cond_signal) {
     62     LOGGER_ASSERT(0 == pthread_cond_signal(&queued_lines_cond_));
     63   }
     64   LOGGER_ASSERT(0 == pthread_join(thread_, NULL));
     65 }
     66 
     67 Logger::Logger() : verbosity_(20), log_fd_(-1), thread_running_(false) {
     68   LOGGER_ASSERT(0 == pthread_mutex_init(&queued_lines_mutex_, NULL));
     69   LOGGER_ASSERT(0 == pthread_cond_init(&queued_lines_cond_, NULL));
     70   LOGGER_ASSERT(0 == pthread_cond_init(&full_queue_cond_, NULL));
     71 }
     72 
     73 Logger::~Logger() {
     74   LOGGER_ASSERT(0 == pthread_mutex_destroy(&queued_lines_mutex_));
     75   LOGGER_ASSERT(0 == pthread_cond_destroy(&queued_lines_cond_));
     76   LOGGER_ASSERT(0 == pthread_cond_destroy(&full_queue_cond_));
     77 }
     78 
     79 void Logger::QueueLogLine(string *line) {
     80   LOGGER_ASSERT(line != NULL);
     81   LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_));
     82   if (thread_running_) {
     83     if (queued_lines_.size() >= kMaxQueueSize) {
     84       LOGGER_ASSERT(0 == pthread_cond_wait(&full_queue_cond_,
     85                                            &queued_lines_mutex_));
     86     }
     87     if (queued_lines_.empty()) {
     88       LOGGER_ASSERT(0 == pthread_cond_signal(&queued_lines_cond_));
     89     }
     90     queued_lines_.push_back(line);
     91   } else {
     92     WriteAndDeleteLogLine(line);
     93   }
     94   LOGGER_ASSERT(0 == pthread_mutex_unlock(&queued_lines_mutex_));
     95 }
     96 
     97 namespace {
     98 void WriteToFile(const string& line, int fd) {
     99   LOGGER_ASSERT(write(fd, line.data(), line.size()) ==
    100                 static_cast<ssize_t>(line.size()));
    101 }
    102 }
    103 
    104 void Logger::WriteAndDeleteLogLine(string *line) {
    105   LOGGER_ASSERT(line != NULL);
    106   if (log_fd_ >= 0) {
    107     WriteToFile(*line, log_fd_);
    108   }
    109   WriteToFile(*line, 1);
    110   delete line;
    111 }
    112 
    113 void *Logger::StartRoutine(void *ptr) {
    114   Logger *self = static_cast<Logger*>(ptr);
    115   self->ThreadMain();
    116   return NULL;
    117 }
    118 
    119 void Logger::ThreadMain() {
    120   vector<string*> local_queue;
    121   LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_));
    122 
    123   for (;;) {
    124     if (queued_lines_.empty()) {
    125       LOGGER_ASSERT(0 == pthread_cond_wait(&queued_lines_cond_,
    126                                            &queued_lines_mutex_));
    127       continue;
    128     }
    129 
    130     // We move the log lines into a local queue so we can release the lock
    131     // while writing them to disk, preventing other threads from blocking on
    132     // our writes.
    133     local_queue.swap(queued_lines_);
    134     if (local_queue.size() >= kMaxQueueSize) {
    135       LOGGER_ASSERT(0 == pthread_cond_broadcast(&full_queue_cond_));
    136     }
    137 
    138     // Unlock while we process our local queue.
    139     LOGGER_ASSERT(0 == pthread_mutex_unlock(&queued_lines_mutex_));
    140     for (vector<string*>::const_iterator it = local_queue.begin();
    141          it != local_queue.end(); ++it) {
    142       if (*it == NULL) {
    143         // NULL is guaranteed to be at the end.
    144         return;
    145       }
    146       WriteAndDeleteLogLine(*it);
    147     }
    148     local_queue.clear();
    149     // We must hold the lock at the start of each iteration of this for loop.
    150     LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_));
    151   }
    152 }
    153