AI 24/25 Project Software
Documentation for the AI 24/25 course programming project software
Loading...
Searching...
No Matches
logging.h
1#ifndef UTILS_LOGGING_H
2#define UTILS_LOGGING_H
3
4#include "downward/utils/exceptions.h"
5#include "downward/utils/system.h"
6#include "downward/utils/timer.h"
7
8#include <memory>
9#include <ostream>
10#include <ranges>
11#include <string>
12#include <vector>
13
14namespace utils {
15// See add_log_options_to_feature for documentation.
16enum class Verbosity { SILENT, NORMAL, VERBOSE, DEBUG };
17
18/*
19 Simple line-based logger that prepends time and peak memory info to each line
20 of output. Lines should be eventually terminated by endl. Logs are written to
21 stdout.
22
23 Internal class encapsulated by LogProxy.
24*/
25class Log {
26 std::ostream& stream;
27 const Verbosity verbosity;
28 bool line_has_started;
29
30public:
31 explicit Log(Verbosity verbosity)
32 : stream(std::cout)
33 , verbosity(verbosity)
34 , line_has_started(false)
35 {
36 }
37
38 template <typename T>
39 Log& operator<<(const T& elem)
40 {
41 if (!line_has_started) {
42 line_has_started = true;
43 stream << "[t=" << g_timer << ", " << get_peak_memory_in_kb()
44 << " KB] ";
45 }
46
47 stream << elem;
48 return *this;
49 }
50
51 using manip_function = std::ostream& (*)(std::ostream&);
52 Log& operator<<(manip_function f)
53 {
54 if (f == static_cast<manip_function>(&std::endl)) {
55 line_has_started = false;
56 }
57
58 stream << f;
59 return *this;
60 }
61
62 Verbosity get_verbosity() const { return verbosity; }
63};
64
65template <typename T>
66concept Dumpable = requires(T t, std::ostream& out) { out << t; };
67
68template <typename T>
69struct RecursivelyDumpableHelper : std::false_type {};
70
71template <std::ranges::input_range T>
72struct RecursivelyDumpableHelper<T>
73 : std::conditional_t<
74 !Dumpable<T>,
75 std::conditional_t<
76 !Dumpable<std::ranges::range_reference_t<T>>,
77 RecursivelyDumpableHelper<std::ranges::range_reference_t<T>>,
78 std::true_type>,
79 std::false_type> {};
80
81template <typename T>
82concept RecursivelyDumpable = RecursivelyDumpableHelper<T>::value;
83
84/*
85 This class wraps Log which holds onto the used stream (currently hard-coded
86 to be cout) and any further options for modifying output (currently only
87 the verbosity level).
88
89 The wrapped class Log is a line-based logger that prepends time and peak
90 memory info to each line of output. Lines should be eventually terminated by
91 endl. Logs are written to stdout.
92
93 We need to have this wrapper because we want to be able to return plain
94 objects (as opposed to pointers) in function get_log_from_options below,
95 which internally returns a wrapper to the default Log if default options
96 are specified or a new instance if non-default options are specified.
97*/
98class LogProxy {
99private:
100 std::shared_ptr<Log> log;
101
102public:
103 explicit LogProxy(const std::shared_ptr<Log>& log)
104 : log(log)
105 {
106 }
107
108 LogProxy& operator<<(const Dumpable auto& elem)
109 {
110 (*log) << elem;
111 return *this;
112 }
113
114 using manip_function = std::ostream& (*)(std::ostream&);
115 LogProxy& operator<<(manip_function f)
116 {
117 (*log) << f;
118 return *this;
119 }
120
121 bool is_at_least_normal() const
122 {
123 return log->get_verbosity() >= Verbosity::NORMAL;
124 }
125
126 bool is_at_least_verbose() const
127 {
128 return log->get_verbosity() >= Verbosity::VERBOSE;
129 }
130
131 bool is_at_least_debug() const
132 {
133 return log->get_verbosity() >= Verbosity::DEBUG;
134 }
135
136 // TODO: implement an option for logging warnings.
137 bool is_warning() const { return true; }
138
139 template <typename T>
140 friend LogProxy& operator<<(LogProxy& stream, const T& range)
141 requires(RecursivelyDumpable<T>)
142 {
143 stream << "[";
144 auto it = std::ranges::begin(range);
145 auto end = std::ranges::end(range);
146 if (it != end) {
147 for (;;) {
148 stream << *it;
149 if (++it == end) break;
150 stream << ", ";
151 }
152 }
153 stream << "]";
154 return stream;
155 }
156};
157
158/*
159 In the long term, this should not be global anymore. Instead, local LogProxy
160 objects should be used everywhere. For classes constructed from the command
161 line, they are parsed from Options. For other classes and functions, they
162 must be passed in by the caller.
163*/
164extern LogProxy g_log;
165
166extern LogProxy get_log_for_verbosity(const Verbosity& verbosity);
167extern LogProxy get_silent_log();
168
169class ContextError : public utils::Exception {
170public:
171 explicit ContextError(const std::string& msg);
172};
173
174class Context {
175protected:
176 static const std::string INDENT;
177 size_t initial_stack_size =
178 0; // TODO: Can be removed once we got rid of LazyValues
179 std::vector<std::string> block_stack;
180
181public:
182 explicit Context() = default;
183 Context(const Context& context);
184 virtual ~Context();
185 virtual std::string
186 decorate_block_name(const std::string& block_name) const;
187 void enter_block(const std::string& block_name);
188 void leave_block(const std::string& block_name);
189 std::string str() const;
190
191 [[noreturn]]
192 virtual void error(const std::string& message) const;
193 virtual void warn(const std::string& message) const;
194};
195
196class MemoryContext : public Context {
197 // The following constants affect the formatting of output.
198 static const int MEM_FIELD_WIDTH = 7;
199 static const int TIME_FIELD_WIDTH = 7;
200
201public:
202 virtual std::string
203 decorate_block_name(const std::string& block_name) const override;
204};
205
206extern MemoryContext _memory_context;
207
208class TraceBlock {
209 Context& context;
210 std::string block_name;
211
212public:
213 explicit TraceBlock(Context& context, const std::string& block_name);
214 ~TraceBlock();
215};
216
217extern void trace_memory(const std::string& msg = "");
218} // namespace utils
219
220namespace std {
221template <class T>
222ostream& operator<<(ostream& stream, const vector<T>& vec)
223{
224 stream << "[";
225 for (size_t i = 0; i < vec.size(); ++i) {
226 if (i != 0) stream << ", ";
227 stream << vec[i];
228 }
229 stream << "]";
230 return stream;
231}
232} // namespace std
233
234#endif
STL namespace.