| 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 | |