logging.hh revision 12334:e0ab29a34764
1/*
2 * Copyright (c) 2014, 2017 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Nathan Binkert
41 *          Dave Greene
42 *          Andreas Sandberg
43 */
44
45#ifndef __BASE_LOGGING_HH__
46#define __BASE_LOGGING_HH__
47
48#include <cassert>
49#include <cstdlib>
50#include <iostream>
51#include <utility>
52
53#include "base/compiler.hh"
54#include "base/cprintf.hh"
55
56#if defined(__SUNPRO_CC)
57#define __FUNCTION__ "how to fix me?"
58#endif
59
60class Logger
61{
62  public:
63    enum LogLevel {
64        PANIC = 0,
65        FATAL,
66        WARN,
67        INFO,
68        HACK,
69        NUM_LOG_LEVELS,
70    };
71
72    /**
73     * Set the active log level.
74     *
75     * All levels that are lower or equal to the selected log level
76     * will be activated.
77     *
78     * @param ll Maximum log level to print
79     */
80    static void setLevel(LogLevel ll);
81
82    /**
83     * Get a Logger corresponding to a specific log level
84     *
85     * @param ll Log level to access
86     * @return Reference to the requested logger
87     */
88    static Logger &get(LogLevel ll);
89
90  public:
91    Logger(std::ostream &stream, const char *prefix);
92    virtual ~Logger() {};
93
94    template<typename ...Args> void
95    print(const char *func, const char *file, int line,
96          const char *format, const Args &...args)
97    {
98        if (!enabled)
99            return;
100
101        if (prefix)
102            stream << prefix << ": ";
103        ccprintf(stream, format, args...);
104
105        printEpilogue(func, file, line, format);
106    }
107
108    template<typename ...Args> void
109    print(const char *func, const char *file, int line,
110          const std::string &format, const Args &...args)
111    {
112        print(func, file, line, format.c_str(), args...);
113    }
114
115  protected:
116    virtual void printEpilogue(const char *func, const char *file, int line,
117                               const char *format);
118
119  public:
120    bool enabled;
121    bool verbose;
122
123  protected:
124    std::ostream &stream;
125    const char *prefix;
126};
127
128#define exit_message(logger, code, ...)                                 \
129    do {                                                                \
130        logger.print(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__);    \
131        if (code < 0)                                                   \
132            ::abort();                                                  \
133        else                                                            \
134            ::exit(code);                                               \
135    } while (0)
136
137//
138// This implements a cprintf based panic() function.  panic() should
139// be called when something happens that should never ever happen
140// regardless of what the user does (i.e., an acutal m5 bug).  panic()
141// calls abort which can dump core or enter the debugger.
142//
143//
144#define panic(...) exit_message(::Logger::get(::Logger::PANIC), -1, \
145                                __VA_ARGS__)
146
147//
148// This implements a cprintf based fatal() function.  fatal() should
149// be called when the simulation cannot continue due to some condition
150// that is the user's fault (bad configuration, invalid arguments,
151// etc.) and not a simulator bug.  fatal() calls  abort() like
152// panic() does.
153//
154#define fatal(...) exit_message(::Logger::get(::Logger::FATAL), 1, \
155                                __VA_ARGS__)
156
157/**
158 * Conditional panic macro that checks the supplied condition and only panics
159 * if the condition is true and allows the programmer to specify diagnostic
160 * printout.  Useful to replace if + panic, or if + print + assert, etc.
161 *
162 * @param cond Condition that is checked; if true -> panic
163 * @param ...  Printf-based format string with arguments, extends printout.
164 */
165#define panic_if(cond, ...)                                  \
166    do {                                                     \
167        if ((cond)) {                                        \
168            panic("panic condition " # cond " occurred: %s", \
169                  csprintf(__VA_ARGS__));                    \
170        }                                                    \
171    } while (0)
172
173
174/**
175 * Conditional fatal macro that checks the supplied condition and only causes a
176 * fatal error if the condition is true and allows the programmer to specify
177 * diagnostic printout.  Useful to replace if + fatal, or if + print + assert,
178 * etc.
179 *
180 * @param cond Condition that is checked; if true -> fatal
181 * @param ...  Printf-based format string with arguments, extends printout.
182 */
183#define fatal_if(cond, ...)                                     \
184    do {                                                        \
185        if ((cond)) {                                           \
186            fatal("fatal condition " # cond " occurred: %s",    \
187                  csprintf(__VA_ARGS__));                       \
188        }                                                       \
189    } while (0)
190
191
192#define base_message(logger, ...)                                       \
193    logger.print(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
194
195// Only print the message the first time this expression is
196// encountered.  i.e.  This doesn't check the string itself and
197// prevent duplicate strings, this prevents the statement from
198// happening more than once. So, even if the arguments change and that
199// would have resulted in a different message thoes messages would be
200// supressed.
201#define base_message_once(...) do {                     \
202        static bool once = false;                       \
203        if (!once) {                                    \
204            base_message(__VA_ARGS__);                  \
205            once = true;                                \
206        }                                               \
207    } while (0)
208
209
210#define warn(...) \
211    base_message(::Logger::get(::Logger::WARN), __VA_ARGS__)
212#define inform(...) \
213    base_message(::Logger::get(::Logger::INFO), __VA_ARGS__)
214#define hack(...) \
215    base_message(::Logger::get(::Logger::HACK), __VA_ARGS__)
216
217#define warn_once(...) \
218    base_message_once(::Logger::get(::Logger::WARN), __VA_ARGS__)
219#define inform_once(...) \
220    base_message_once(::Logger::get(::Logger::INFO), __VA_ARGS__)
221#define hack_once(...) \
222    base_message_once(::Logger::get(::Logger::HACK), __VA_ARGS__)
223
224/**
225 * Conditional warning macro that checks the supplied condition and
226 * only prints a warning if the condition is true. Useful to replace
227 * if + warn.
228 *
229 * @param cond Condition that is checked; if true -> warn
230 * @param ...  Printf-based format string with arguments, extends printout.
231 */
232#define warn_if(cond, ...) \
233    do { \
234        if ((cond)) \
235            warn(__VA_ARGS__); \
236    } while (0)
237
238/**
239 * The chatty assert macro will function like a normal assert, but will allow
240 * the specification of additional, helpful material to aid debugging why the
241 * assertion actually failed.  Like the normal assertion, the chatty_assert
242 * will not be active in fast builds.
243 *
244 * @param cond Condition that is checked; if false -> assert
245 * @param ...  Printf-based format string with arguments, extends printout.
246 */
247#ifdef NDEBUG
248#define chatty_assert(cond, ...)
249#else //!NDEBUG
250#define chatty_assert(cond, ...)                                        \
251    do {                                                                \
252        if (!(cond))                                                    \
253            panic("assert(" # cond ") failed: %s", csprintf(__VA_ARGS__)); \
254    } while (0)
255#endif // NDEBUG
256#endif // __BASE_LOGGING_HH__
257