benchmarks compiles with clang
[c11concurrency-benchmarks.git] / mabain / src / logger.cpp
1 /**
2  * Copyright (C) 2017 Cisco Inc.
3  *
4  * This program is free software: you can redistribute it and/or  modify
5  * it under the terms of the GNU General Public License, version 2,
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 // @author Changxue Deng <chadeng@cisco.com>
18
19 #include <stdarg.h>
20 #include <iostream>
21 #include <unistd.h>
22
23 #include "logger.h"
24 #include "error.h"
25
26 #define MAX_NUM_LOG 10
27
28 namespace mabain {
29
30 std::string Logger::log_file = "";
31 std::ofstream* Logger::log_stream = NULL;
32 int Logger::log_level_       = LOG_LEVEL_WARN;
33 int Logger::roll_size        = 50*1024*1024;
34 const char* Logger::LOG_LEVEL[4] =
35 {
36     " ERROR: ",
37     " WARN: ",
38     " INFO: ",
39     " DEBUG: "
40 };
41
42 Logger::Logger()
43 {
44 }
45
46 Logger::~Logger()
47 {
48 }
49
50 void Logger::Close()
51 {
52     if(log_stream != NULL)
53     {
54         if(log_stream->is_open())
55             log_stream->close();
56
57         delete log_stream;
58         log_stream = NULL;
59     }
60 }
61
62 // Should only be called by writer for now.
63 // Readers will send logs to stdout or stderr.
64 void Logger::InitLogFile(const std::string &logfile)
65 {
66     if(!logfile.empty())
67     {
68         log_file = logfile;
69         log_level_ = LOG_LEVEL_INFO;
70         log_stream = new std::ofstream();
71         log_stream->open(log_file.c_str(), std::ios::out | std::ios::app);
72     }
73 }
74
75 void Logger::FillDateTime(char *buffer, int bufsize)
76 {
77     time_t rawtime;
78     struct tm timeinfo;
79     time (&rawtime);
80     if(localtime_r(&rawtime, &timeinfo))
81         strftime(buffer, bufsize, "%Y-%m-%d.%X", &timeinfo);
82     else
83         snprintf(buffer, bufsize, "Time unknown");
84 }
85
86 void Logger::Rotate()
87 {
88     if(log_stream == NULL)
89         return;
90     if(log_stream->is_open())
91         log_stream->close();
92
93     std::string filepath_old;
94     std::string filepath_new;
95     for(int i = MAX_NUM_LOG-2; i > 0; i--)
96     {
97         filepath_old = log_file + "." + std::to_string(i);
98         if(access(filepath_old.c_str(), R_OK) == 0)
99         {
100             filepath_new = log_file + "." + std::to_string(i+1);
101             if(rename(filepath_old.c_str(), filepath_new.c_str()))
102                 std::cerr << "failed to move log file\n";
103         }
104     }
105     filepath_new = log_file + ".1";
106     if(rename(log_file.c_str(), filepath_new.c_str()))
107         std::cerr << "failed to move log file\n";
108
109     log_stream->open(log_file.c_str(), std::ios::out | std::ios::app);
110 }
111
112 void Logger::Log(int level, const std::string &message)
113 {
114     if(level > log_level_)
115         return;
116
117     if(log_stream != NULL)
118     {
119         char buffer[80];
120         FillDateTime(buffer, sizeof(buffer));
121         *log_stream << buffer << LOG_LEVEL[level] << message << std::endl;
122         if(log_stream->tellp() > roll_size)
123             Logger::Rotate();
124     }
125     else if(level < LOG_LEVEL_INFO)
126         std::cerr << message << std::endl;
127     else
128         std::cout << message << std::endl;
129 }
130
131 void Logger::Log(int level, const char *format, ... )
132 {
133     if(level > log_level_)
134         return;
135
136     char message[256];
137     va_list args;
138     va_start(args, format);
139     vsprintf(message, format, args);
140     if(log_stream != NULL)
141     {
142         char buffer[64];
143         FillDateTime(buffer, sizeof(buffer));
144         *log_stream << buffer << LOG_LEVEL[level] << message << std::endl;
145         if(log_stream->tellp() > roll_size)
146             Logger::Rotate();
147     }
148     else if(level < LOG_LEVEL_INFO)
149         std::cerr << message << std::endl;
150     else
151         std::cout << message << std::endl;
152     va_end(args);
153 }
154
155 int Logger::SetLogLevel(int level)
156 {
157     if(level < 0 || level > LOG_LEVEL_DEBUG)
158     {
159         Logger::Log(LOG_LEVEL_WARN, "invaid logging level %d", level);
160         return MBError::INVALID_ARG;
161     }
162
163     log_level_ = level;
164
165     return MBError::SUCCESS;
166 }
167
168 std::ofstream* Logger::GetLogStream()
169 {
170     return log_stream;
171 }
172
173 }