simdjson 4.2.2
Ridiculously Fast JSON
Loading...
Searching...
No Matches
logger-inl.h
1#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
2
3#ifndef SIMDJSON_CONDITIONAL_INCLUDE
4#define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
5#include "simdjson/generic/ondemand/base.h"
6#include "simdjson/generic/ondemand/logger.h"
7#include "simdjson/generic/ondemand/json_iterator.h"
8#include "simdjson/generic/ondemand/value_iterator.h"
9#endif // SIMDJSON_CONDITIONAL_INCLUDE
10
11#include <memory>
12#include <cstring>
13
14namespace simdjson {
15namespace SIMDJSON_IMPLEMENTATION {
16namespace ondemand {
17namespace logger {
18
19static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
20static constexpr const int LOG_EVENT_LEN = 20;
21static constexpr const int LOG_BUFFER_LEN = 30;
22static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
23static int log_depth = 0; // Not threadsafe. Log only.
24
25// Helper to turn unprintable or newline characters into spaces
26static inline char printable_char(char c) {
27 if (c >= 0x20) {
28 return c;
29 } else {
30 return ' ';
31 }
32}
33
34template<typename... Args>
35static inline std::string string_format(const std::string& format, const Args&... args)
36{
37 SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
38 int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
39 auto size = static_cast<size_t>(size_s);
40 if (size <= 0) return std::string();
41 std::unique_ptr<char[]> buf(new char[size]);
42 std::snprintf(buf.get(), size, format.c_str(), args...);
43 SIMDJSON_POP_DISABLE_WARNINGS
44 return std::string(buf.get(), buf.get() + size - 1);
45}
46
47static inline log_level get_log_level_from_env()
48{
49 SIMDJSON_PUSH_DISABLE_WARNINGS
50 SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
51 char *lvl = getenv("SIMDJSON_LOG_LEVEL");
52 SIMDJSON_POP_DISABLE_WARNINGS
53 if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
54 return log_level::info;
55}
56
57static inline log_level log_threshold()
58{
59 static log_level threshold = get_log_level_from_env();
60 return threshold;
61}
62
63static inline bool should_log(log_level level)
64{
65 return level >= log_threshold();
66}
67
68inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
69 log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
70}
71
72inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
73 log_line(iter, index, depth, "", type, detail, log_level::info);
74}
75inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
76 log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
77}
78
79inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
80 log_line(iter, index, depth, "+", type, detail, log_level::info);
81 if (LOG_ENABLED) { log_depth++; }
82}
83inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
84 log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
85 if (LOG_ENABLED) { log_depth++; }
86}
87
88inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
89 if (LOG_ENABLED) { log_depth--; }
90 log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
91}
92
93inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
94 log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
95}
96inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
97 log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
98}
99
100inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
101 log_event(iter.json_iter(), type, detail, delta, depth_delta);
102}
103
104inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
105 log_value(iter.json_iter(), type, detail, delta, depth_delta);
106}
107
108inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
109 log_start_value(iter.json_iter(), type, delta, depth_delta);
110}
111
112inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
113 log_end_value(iter.json_iter(), type, delta, depth_delta);
114}
115
116inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
117 log_error(iter.json_iter(), error, detail, delta, depth_delta);
118}
119
120inline void log_headers() noexcept {
121 if (LOG_ENABLED) {
122 if (simdjson_unlikely(should_log(log_level::info))) {
123 // Technically a static variable is not thread-safe, but if you are using threads and logging... well...
124 static bool displayed_hint{false};
125 log_depth = 0;
126 printf("\n");
127 if (!displayed_hint) {
128 // We only print this helpful header once.
129 printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
130 printf("# +array says 'this is where we were when we discovered the start array'\n");
131 printf(
132 "# -array says 'this is where we were when we ended the array'\n");
133 printf("# skip says 'this is a structural or value I am skipping'\n");
134 printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
135 printf("#\n");
136 printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
137 printf("# in addition to the depth being displayed.\n");
138 printf("#\n");
139 printf("# Every token in the document has a single depth determined by the tokens before it,\n");
140 printf("# and is not affected by what the token actually is.\n");
141 printf("#\n");
142 printf("# Not all structural elements are presented as tokens in the logs.\n");
143 printf("#\n");
144 printf("# We never give control to the user within an empty array or an empty object.\n");
145 printf("#\n");
146 printf("# Inside an array, having a depth greater than the array's depth means that\n");
147 printf("# we are pointing inside a value.\n");
148 printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
149 printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
150 displayed_hint = true;
151 }
152 printf("\n");
153 printf("| %-*s ", LOG_EVENT_LEN, "Event");
154 printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
155 printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
156 // printf("| %-*s ", 5, "Next#");
157 printf("| %-*s ", 5, "Depth");
158 printf("| Detail ");
159 printf("|\n");
160
161 printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
162 printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
163 printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
164 // printf("|%.*s", 5+2, DASHES);
165 printf("|%.*s", 5 + 2, DASHES);
166 printf("|--------");
167 printf("|\n");
168 fflush(stdout);
169 }
170 }
171}
172
173template <typename... Args>
174inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
175 log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
176}
177
178template <typename... Args>
179inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
180 if (LOG_ENABLED) {
181 if (simdjson_unlikely(should_log(level))) {
182 const int indent = depth * 2;
183 const auto buf = iter.token.buf;
184 auto msg = string_format(title, std::forward<Args>(args)...);
185 printf("| %*s%s%-*s ", indent, "", title_prefix,
186 LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
187 {
188 // Print the current structural.
189 printf("| ");
190 // Before we begin, the index might point right before the document.
191 // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
192 if (index < iter._root) {
193 printf("%*s", LOG_BUFFER_LEN, "");
194 } else {
195 auto current_structural = &buf[*index];
196 for (int i = 0; i < LOG_BUFFER_LEN; i++) {
197 printf("%c", printable_char(current_structural[i]));
198 }
199 }
200 printf(" ");
201 }
202 {
203 // Print the next structural.
204 printf("| ");
205 auto next_structural = &buf[*(index + 1)];
206 for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
207 printf("%c", printable_char(next_structural[i]));
208 }
209 printf(" ");
210 }
211 // printf("| %5u ", *(index+1));
212 printf("| %5i ", depth);
213 printf("| %6.*s ", int(detail.size()), detail.data());
214 printf("|\n");
215 fflush(stdout);
216 }
217 }
218}
219
220} // namespace logger
221} // namespace ondemand
222} // namespace SIMDJSON_IMPLEMENTATION
223} // namespace simdjson
224
225#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H
int32_t depth_t
Represents the depth of a JSON value (number of nested arrays/objects).
Definition base.h:18
The top level simdjson namespace, containing everything the library provides.
Definition base.h:8