simdjson  3.11.0
Ridiculously Fast JSON
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 
14 namespace simdjson {
15 namespace SIMDJSON_IMPLEMENTATION {
16 namespace ondemand {
17 namespace logger {
18 
19 static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
20 static constexpr const int LOG_EVENT_LEN = 20;
21 static constexpr const int LOG_BUFFER_LEN = 30;
22 static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
23 static int log_depth = 0; // Not threadsafe. Log only.
24 
25 // Helper to turn unprintable or newline characters into spaces
26 static inline char printable_char(char c) {
27  if (c >= 0x20) {
28  return c;
29  } else {
30  return ' ';
31  }
32 }
33 
34 template<typename... Args>
35 static 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 
47 static 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 
57 static inline log_level log_threshold()
58 {
59  static log_level threshold = get_log_level_from_env();
60  return threshold;
61 }
62 
63 static inline bool should_log(log_level level)
64 {
65  return level >= log_threshold();
66 }
67 
68 inline 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 
72 inline 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 }
75 inline 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 
79 inline 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 }
83 inline 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 
88 inline 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 
93 inline 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 }
96 inline 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 
100 inline 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 
104 inline 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 
108 inline 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 
112 inline 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 
116 inline 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 
120 inline 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 
173 template <typename... Args>
174 inline 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 
178 template <typename... Args>
179 inline 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