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