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