1 /** 2 * Copyright (c) 2007-2012, Timothy Stack 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * * Neither the name of Timothy Stack nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * @file lnav.hh 30 */ 31 32 #ifndef lnav_hh 33 #define lnav_hh 34 35 #include "config.h" 36 37 #include <signal.h> 38 #include <sys/time.h> 39 40 #include <map> 41 #include <set> 42 #include <list> 43 #include <stack> 44 #include <memory> 45 #include <unordered_map> 46 47 #include "base/future_util.hh" 48 #include "base/isc.hh" 49 #include "safe/safe.h" 50 #include "logfile.hh" 51 #include "hist_source.hh" 52 #include "statusview_curses.hh" 53 #include "listview_curses.hh" 54 #include "top_status_source.hh" 55 #include "bottom_status_source.hh" 56 #include "doc_status_source.hh" 57 #include "grep_highlighter.hh" 58 #include "db_sub_source.hh" 59 #include "textfile_sub_source.hh" 60 #include "log_vtab_impl.hh" 61 #include "readline_curses.hh" 62 #include "piper_proc.hh" 63 #include "relative_time.hh" 64 #include "log_format_loader.hh" 65 #include "spectro_source.hh" 66 #include "command_executor.hh" 67 #include "plain_text_source.hh" 68 #include "input_dispatcher.hh" 69 #include "filter_sub_source.hh" 70 #include "files_sub_source.hh" 71 #include "filter_status_source.hh" 72 #include "preview_status_source.hh" 73 #include "sql_util.hh" 74 #include "archive_manager.hh" 75 #include "file_collection.hh" 76 #include "view_helpers.hh" 77 78 /** The command modes that are available while viewing a file. */ 79 typedef enum { 80 LNM_PAGING, 81 LNM_FILTER, 82 LNM_FILES, 83 LNM_COMMAND, 84 LNM_SEARCH, 85 LNM_SEARCH_FILTERS, 86 LNM_SEARCH_FILES, 87 LNM_CAPTURE, 88 LNM_SQL, 89 LNM_EXEC, 90 LNM_USER, 91 } ln_mode_t; 92 93 enum { 94 LNB_SYSLOG, 95 LNB__MAX, 96 97 LNB_TIMESTAMP, 98 LNB_HELP, 99 LNB_HEADLESS, 100 LNB_QUIET, 101 LNB_CHECK_CONFIG, 102 LNB_INSTALL, 103 LNB_UPDATE_FORMATS, 104 LNB_VERBOSE, 105 LNB_SECURE_MODE, 106 LNB_NO_DEFAULT, 107 }; 108 109 /** Flags set on the lnav command-line. */ 110 typedef enum { 111 LNF_SYSLOG = (1L << LNB_SYSLOG), 112 113 LNF_TIMESTAMP = (1L << LNB_TIMESTAMP), 114 LNF_HELP = (1L << LNB_HELP), 115 LNF_HEADLESS = (1L << LNB_HEADLESS), 116 LNF_QUIET = (1L << LNB_QUIET), 117 LNF_CHECK_CONFIG = (1L << LNB_CHECK_CONFIG), 118 LNF_INSTALL = (1L << LNB_INSTALL), 119 LNF_UPDATE_FORMATS = (1L << LNB_UPDATE_FORMATS), 120 LNF_VERBOSE = (1L << LNB_VERBOSE), 121 LNF_SECURE_MODE = (1L << LNB_SECURE_MODE), 122 LNF_NO_DEFAULT = (1L << LNB_NO_DEFAULT), 123 124 LNF__ALL = (LNF_SYSLOG|LNF_HELP), 125 } lnav_flags_t; 126 127 extern const char *lnav_zoom_strings[]; 128 129 /** The status bars. */ 130 typedef enum { 131 LNS_TOP, 132 LNS_BOTTOM, 133 LNS_FILTER, 134 LNS_FILTER_HELP, 135 LNS_DOC, 136 LNS_PREVIEW, 137 138 LNS__MAX 139 } lnav_status_t; 140 141 typedef std::pair<int, int> ppid_time_pair_t; 142 typedef std::pair<ppid_time_pair_t, ghc::filesystem::path> session_pair_t; 143 144 class input_state_tracker : public log_state_dumper { 145 public: input_state_tracker()146 input_state_tracker() : ist_index(0) { 147 memset(this->ist_recent_key_presses, 0, sizeof(this->ist_recent_key_presses)); 148 }; 149 log_state()150 void log_state() override { 151 log_info("recent_key_presses: index=%d", this->ist_index); 152 for (int lpc = 0; lpc < COUNT; lpc++) { 153 log_msg_extra(" 0x%x (%c)", this->ist_recent_key_presses[lpc], 154 this->ist_recent_key_presses[lpc]); 155 } 156 log_msg_extra_complete(); 157 }; 158 push_back(int ch)159 void push_back(int ch) { 160 this->ist_recent_key_presses[this->ist_index % COUNT] = ch; 161 this->ist_index = (this->ist_index + 1) % COUNT; 162 }; 163 164 private: 165 static const int COUNT = 10; 166 167 int ist_recent_key_presses[COUNT]; 168 size_t ist_index; 169 }; 170 171 struct key_repeat_history { 172 int krh_key{0}; 173 int krh_count{0}; 174 vis_line_t krh_start_line{0_vl}; 175 struct timeval krh_last_press_time{0, 0}; 176 updatekey_repeat_history177 void update(int ch, vis_line_t top) { 178 struct timeval now, diff; 179 180 gettimeofday(&now, nullptr); 181 timersub(&now, &this->krh_last_press_time, &diff); 182 if (diff.tv_sec >= 1 || diff.tv_usec > (750 * 1000)) { 183 this->krh_key = 0; 184 this->krh_count = 0; 185 } 186 this->krh_last_press_time = now; 187 188 if (this->krh_key == ch) { 189 this->krh_count += 1; 190 } else { 191 this->krh_key = ch; 192 this->krh_count = 1; 193 this->krh_start_line = top; 194 } 195 }; 196 }; 197 198 struct lnav_data_t { 199 std::map<std::string, std::list<session_pair_t>> ld_session_id; 200 time_t ld_session_time; 201 time_t ld_session_load_time; 202 const char * ld_program_name; 203 const char * ld_debug_log_name; 204 205 std::list<std::string> ld_commands; 206 bool ld_cmd_init_done; 207 bool ld_session_loaded; 208 std::vector<ghc::filesystem::path> ld_config_paths; 209 file_collection ld_active_files; 210 std::list<std::pair<std::string, int> > ld_files_to_front; 211 std::string ld_pt_search; 212 time_t ld_pt_min_time; 213 time_t ld_pt_max_time; 214 bool ld_stdout_used; 215 sig_atomic_t ld_looping; 216 sig_atomic_t ld_winched; 217 sig_atomic_t ld_child_terminated; 218 unsigned long ld_flags; 219 WINDOW * ld_window; 220 ln_mode_t ld_mode; 221 ln_mode_t ld_last_config_mode{LNM_FILTER}; 222 223 statusview_curses ld_status[LNS__MAX]; 224 top_status_source ld_top_source; 225 bottom_status_source ld_bottom_source; 226 filter_status_source ld_filter_status_source; 227 filter_help_status_source ld_filter_help_status_source; 228 doc_status_source ld_doc_status_source; 229 preview_status_source ld_preview_status_source; 230 bool ld_preview_hidden; 231 int64_t ld_preview_generation{0}; 232 action_broadcaster<listview_curses> ld_scroll_broadcaster; 233 action_broadcaster<listview_curses> ld_view_stack_broadcaster; 234 235 plain_text_source ld_help_source; 236 237 plain_text_source ld_doc_source; 238 textview_curses ld_doc_view; 239 filter_sub_source ld_filter_source; 240 textview_curses ld_filter_view; 241 files_sub_source ld_files_source; 242 files_overlay_source ld_files_overlay; 243 textview_curses ld_files_view; 244 plain_text_source ld_example_source; 245 textview_curses ld_example_view; 246 plain_text_source ld_match_source; 247 textview_curses ld_match_view; 248 plain_text_source ld_preview_source; 249 textview_curses ld_preview_view; 250 251 view_stack<textview_curses> ld_view_stack; 252 textview_curses *ld_last_view; 253 textview_curses ld_views[LNV__MAX]; 254 std::shared_ptr<grep_proc<vis_line_t>> ld_meta_search; 255 vis_line_t ld_search_start_line; 256 readline_curses * ld_rl_view; 257 258 logfile_sub_source ld_log_source; 259 hist_source2 ld_hist_source2; 260 int ld_zoom_level; 261 spectrogram_source ld_spectro_source; 262 263 textfile_sub_source ld_text_source; 264 265 std::map<textview_curses *, int> ld_last_user_mark; 266 std::map<textview_curses *, int> ld_select_start; 267 268 db_label_source ld_db_row_source; 269 db_overlay_source ld_db_overlay; 270 std::vector<std::string> ld_db_key_names; 271 272 vis_line_t ld_last_pretty_print_top; 273 274 std::unique_ptr<log_vtab_manager> ld_vtab_manager; 275 auto_mem<sqlite3, sqlite_close_wrapper> ld_db; 276 277 std::unordered_map<std::string, std::string> ld_table_ddl; 278 279 std::list<pid_t> ld_children; 280 std::list<std::shared_ptr<piper_proc>> ld_pipers; 281 282 input_state_tracker ld_input_state; 283 input_dispatcher ld_input_dispatcher; 284 285 exec_context ld_exec_context; 286 287 int ld_fifo_counter; 288 289 struct key_repeat_history ld_key_repeat_history; 290 }; 291 292 struct static_service {}; 293 294 class main_looper : public isc::service<main_looper>, public static_service { 295 public: 296 }; 297 298 extern struct lnav_data_t lnav_data; 299 300 extern readline_context::command_map_t lnav_commands; 301 extern const int ZOOM_LEVELS[]; 302 extern const ssize_t ZOOM_COUNT; 303 304 #define HELP_MSG_1(x, msg) \ 305 "Press '" ANSI_BOLD(#x) "' " msg 306 307 #define HELP_MSG_2(x, y, msg) \ 308 "Press " ANSI_BOLD(#x) "/" ANSI_BOLD(#y) " " msg 309 310 void rebuild_hist(); 311 size_t rebuild_indexes(nonstd::optional<ui_clock::time_point> deadline = nonstd::nullopt); 312 void rebuild_indexes_repeatedly(); 313 314 bool setup_logline_table(exec_context &ec); 315 316 bool rescan_files(bool required = false); 317 bool update_active_files(const file_collection& new_files); 318 319 void wait_for_children(); 320 321 textview_curses *get_textview_for_mode(ln_mode_t mode); 322 323 #endif 324