1 | namespace simdjson { |
2 | namespace SIMDJSON_IMPLEMENTATION { |
3 | namespace ondemand { |
4 | namespace logger { |
5 | |
6 | static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------" ; |
7 | static constexpr const int LOG_EVENT_LEN = 20; |
8 | static constexpr const int LOG_BUFFER_LEN = 30; |
9 | static constexpr const int LOG_SMALL_BUFFER_LEN = 10; |
10 | static int log_depth = 0; // Not threadsafe. Log only. |
11 | |
12 | // Helper to turn unprintable or newline characters into spaces |
13 | static inline char printable_char(char c) { |
14 | if (c >= 0x20) { |
15 | return c; |
16 | } else { |
17 | return ' '; |
18 | } |
19 | } |
20 | |
21 | inline 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 | |
25 | inline 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 | } |
28 | inline 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 | |
32 | inline 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 | } |
36 | inline 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 | |
41 | inline 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 | |
46 | inline 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 | } |
49 | inline 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 | |
53 | inline 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 | |
57 | inline 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 | |
61 | inline 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 | |
65 | inline 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 | |
69 | inline 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 | |
73 | inline 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 | |
124 | inline 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 | } |
127 | 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) 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 | |