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