P4C
The P4 Compiler
Loading...
Searching...
No Matches
log.h
1/*
2Copyright 2013-present Barefoot Networks, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef LIB_LOG_H_
18#define LIB_LOG_H_
19
20#include <functional>
21#include <iostream>
22#include <set>
23#include <sstream>
24#include <vector>
25
26#include "config.h"
27#include "indent.h"
28#include "stringify.h"
29
30#ifndef __GNUC__
31#define __attribute__(X)
32#endif
33
34namespace P4 {
35namespace Log {
36namespace Detail {
37// The global verbosity level.
38extern int verbosity;
39
40// A cache of the maximum log level requested for any file.
41extern int maximumLogLevel;
42
43// Used to restrict logging to a specific IR context.
44extern bool enableLoggingGlobally;
45extern bool enableLoggingInContext; // if enableLoggingGlobally is true, this is ignored.
46
47// Look up the log level of @file.
48int fileLogLevel(const char *file);
49std::ostream &fileLogOutput(const char *file);
50
51// A utility class used to prepend file and log level information to logging output.
52// also controls indent control and locking for multithreaded use
54 const char *fn;
55 int level;
56 static int ostream_xalloc;
57 static void setup_ostream_xalloc(std::ostream &);
58 friend std::ostream &operator<<(std::ostream &, const OutputLogPrefix &);
59 friend std::ostream &clearPrefix(std::ostream &out);
60#ifdef MULTITHREAD
61 struct lock_t;
62 mutable lock_t *lock = nullptr;
63#endif // MULTITHREAD
64 public:
65 OutputLogPrefix(const char *f, int l) : fn(f), level(l) {}
67 static void indent(std::ostream &out);
68};
69
70void addInvalidateCallback(void (*)(void));
71std::ostream &clearPrefix(std::ostream &out);
72} // namespace Detail
73
74inline std::ostream &endl(std::ostream &out) {
75 out << std::endl;
76 Detail::OutputLogPrefix::indent(out);
77 return out;
78}
79using ::P4::IndentCtl::indent;
80using ::P4::IndentCtl::TempIndent;
81using ::P4::IndentCtl::unindent;
82
83inline bool fileLogLevelIsAtLeast(const char *file, int level) {
84 // If there's no file with a log level of at least @level, we don't need to do
85 // the more expensive per-file check.
86 if (Detail::maximumLogLevel < level) {
87 return false;
88 }
89
90 return Detail::fileLogLevel(file) >= level;
91}
92
93// Process @spec and update the log level requested for the appropriate file.
94void addDebugSpec(const char *spec);
95
96inline bool verbose() { return Detail::verbosity > 0; }
97inline int verbosity() { return Detail::verbosity; }
98inline bool enableLogging() {
99 return Detail::enableLoggingGlobally || Detail::enableLoggingInContext;
100}
101void increaseVerbosity();
102
103} // namespace Log
104} // namespace P4
105
106#ifndef MAX_LOGGING_LEVEL
107// can be set on build command line and disables higher logging levels at compile time
108#define MAX_LOGGING_LEVEL 10
109#endif
110
111// NOLINTBEGIN(bugprone-macro-parentheses)
112#define LOGGING_FEATURE(TAG, N) \
113 ((N) <= MAX_LOGGING_LEVEL && P4::Log::fileLogLevelIsAtLeast(TAG, N) && P4::Log::enableLogging())
114#define LOGGING(N) LOGGING_FEATURE(__FILE__, N)
115
116#define LOGN(N, X) \
117 (LOGGING(N) ? P4::Log::Detail::fileLogOutput(__FILE__) \
118 << P4::Log::Detail::OutputLogPrefix(__FILE__, N) << X \
119 << P4::Log::Detail::clearPrefix << std::endl \
120 : std::clog)
121#define LOG1(X) LOGN(1, X)
122#define LOG2(X) LOGN(2, X)
123#define LOG3(X) LOGN(3, X)
124#define LOG4(X) LOGN(4, X)
125#define LOG5(X) LOGN(5, X)
126#define LOG6(X) LOGN(6, X)
127#define LOG7(X) LOGN(7, X)
128#define LOG8(X) LOGN(8, X)
129#define LOG9(X) LOGN(9, X)
130
131#define LOGN_UNINDENT(N) \
132 (LOGGING(N) ? P4::Log::Detail::fileLogOutput(__FILE__) << P4::IndentCtl::unindent : std::clog)
133#define LOG1_UNINDENT LOGN_UNINDENT(1)
134#define LOG2_UNINDENT LOGN_UNINDENT(2)
135#define LOG3_UNINDENT LOGN_UNINDENT(3)
136#define LOG4_UNINDENT LOGN_UNINDENT(4)
137#define LOG5_UNINDENT LOGN_UNINDENT(5)
138#define LOG6_UNINDENT LOGN_UNINDENT(6)
139#define LOG7_UNINDENT LOGN_UNINDENT(7)
140#define LOG8_UNINDENT LOGN_UNINDENT(8)
141#define LOG9_UNINDENT LOGN_UNINDENT(9)
142
143#define LOG_FEATURE(TAG, N, X) \
144 (LOGGING_FEATURE(TAG, N) ? P4::Log::Detail::fileLogOutput(TAG) \
145 << P4::Log::Detail::OutputLogPrefix(TAG, N) << X << std::endl \
146 : std::clog)
147
148#define P4C_ERROR(X) (std::clog << "ERROR: " << X << std::endl)
149#define P4C_WARNING(X) (P4::Log::verbose() ? std::clog << "WARNING: " << X << std::endl : std::clog)
150#define ERRWARN(C, X) ((C) ? P4C_ERROR(X) : P4C_WARNING(X))
151// NOLINTEND(bugprone-macro-parentheses)
152
153namespace P4 {
154
155static inline std::ostream &operator<<(std::ostream &out,
156 std::function<std::ostream &(std::ostream &)> fn) {
157 return fn(out);
158}
159
163template <class Cont>
164std::ostream &format_container(std::ostream &out, const Cont &container, char lbrace, char rbrace) {
165 std::vector<std::string> elems;
166 bool foundnl = false;
167 for (auto &el : container) {
168 std::stringstream tmp;
169 tmp << el;
170 elems.emplace_back(tmp.str());
171 if (!foundnl) foundnl = elems.back().find('\n') != std::string::npos;
172 }
173 if (foundnl) {
174 for (auto &el : elems) {
175 out << Log::endl << Log::indent;
176 for (auto &ch : el) {
177 if (ch == '\n')
178 out << Log::endl;
179 else
180 out << ch;
181 }
182 out << Log::unindent;
183 }
184 } else {
185 const char *sep = " ";
186 out << lbrace;
187 for (auto &el : elems) {
188 out << sep << el;
189 sep = ", ";
190 }
191 out << (sep + 1) << rbrace;
192 }
193
194 return out;
195}
196
197template <class T>
198std::ostream &operator<<(std::ostream &out, const std::vector<T> &vec) {
199 return format_container(out, vec, '[', ']');
200}
201
202template <class T>
203std::ostream &operator<<(std::ostream &out, const std::set<T> &set) {
204 return format_container(out, set, '(', ')');
205}
206
207} // namespace P4
208
209#endif /* LIB_LOG_H_ */
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
std::ostream & format_container(std::ostream &out, const Cont &container, char lbrace, char rbrace)
Definition log.h:164