jnav 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,186 @@
1
+ Metadata-Version: 2.4
2
+ Name: jnav
3
+ Version: 1.0.0
4
+ Summary: Interactive JSON log viewer with jq filtering for the terminal
5
+ Keywords: json,log,viewer,jq,tui,terminal
6
+ Author: Tibo Clausen
7
+ License-Expression: GPL-3.0-only
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: System Administrators
12
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Classifier: Topic :: System :: Logging
15
+ Classifier: Topic :: Utilities
16
+ Requires-Dist: textual>=1.0.0
17
+ Requires-Dist: click>=8.1.0
18
+ Requires-Dist: jq>=1.8.0
19
+ Requires-Dist: python-json-logger>=4.0.0
20
+ Requires-Dist: aioreactive>=0.20.0
21
+ Requires-Dist: orjson>=3.11.8
22
+ Requires-Dist: pydantic>=2.12.5
23
+ Requires-Dist: platformdirs>=4.0.0
24
+ Requires-Python: >=3.14
25
+ Project-URL: Repository, https://github.com/XenotriX/jnav
26
+ Description-Content-Type: text/markdown
27
+
28
+ <p>
29
+ <picture>
30
+ <source media="(prefers-color-scheme: dark)" srcset="https://github.com/XenotriX/jnav/blob/d28e3701ec1fa795958db0da7293169ff2887e58/docs/logo/jnav_logo_dark.svg">
31
+ <source media="(prefers-color-scheme: light)" srcset="https://github.com/XenotriX/jnav/blob/d28e3701ec1fa795958db0da7293169ff2887e58/docs/logo/jnav_logo_light.svg">
32
+ <img alt="jnav" src="https://github.com/XenotriX/jnav/blob/d28e3701ec1fa795958db0da7293169ff2887e58/docs/logo/jnav_logo_dark.svg">
33
+ </picture>
34
+ </p>
35
+
36
+ Interactive JSON log viewer with [jq](https://jqlang.github.io/jq/) filtering. Navigate, search, filter, and inspect structured logs in the terminal.
37
+
38
+ ![screenshot](https://raw.githubusercontent.com/XenotriX/jnav/360911e954d91e267616508384ca2e7814c22913/screenshot.png)
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ uv tool install jnav
44
+ ```
45
+
46
+ or
47
+
48
+ ```bash
49
+ pipx install jnav
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ ```bash
55
+ # Open a log file
56
+ $ jnav app.log
57
+
58
+ # Follow the file for new entries (like tail -f)
59
+ $ jnav --follow app.log
60
+
61
+ # Pipe JSONL from stdin
62
+ $ cat logs.jsonl | jnav
63
+ ```
64
+
65
+ ## Features
66
+
67
+ ### Filtering
68
+
69
+ Filters use jq expressions. Clauses are organized in a tree of AND/OR groups, which gets compiled into a single jq expression used to evaluate each entry.
70
+
71
+ ```python
72
+ .level == "error" # exact match
73
+ .data.user_id | IN("abc123", "def456", "ghi789") # match any of
74
+ .message | contains("timeout") # substring
75
+ .message | test("connection (refused|reset)") # regex
76
+ .status >= 500 # numeric comparison
77
+ .items | any(.name == "widget") # list predicate
78
+ ```
79
+
80
+ https://github.com/user-attachments/assets/4c5fa668-7c37-4b59-97f5-4962aeb12504
81
+
82
+ ### Selected Fields
83
+
84
+ Selectors are jq expressions evaluated per entry, rendered inline next to the summary. They can index arrays, aggregate, or reshape strings.
85
+
86
+ ```python
87
+ .status # plain field
88
+ .items[0].name # array index
89
+ .items | length # computed
90
+ .items | map("\(.name): \(.qty)") # string interpolation over a list
91
+ .build | split("-")[1] | tonumber # extract a number from a string
92
+ .request.headers.user_agent # deep path
93
+ ```
94
+
95
+ Add from the detail panel with `s`, or open the selectors manager with `S` to add, edit, reorder, and toggle them.
96
+
97
+
98
+ https://github.com/user-attachments/assets/a9e93048-c3e8-44e6-9f82-727b8e9f8d10
99
+
100
+ ### JSON String Expansion
101
+
102
+ Values that are JSON-encoded strings (e.g. `"data": "{\"key\": \"value\"}"`) are automatically parsed and displayed as nested objects. The tree view shows `"{}"` in italic to distinguish them from real objects. Filters and selectors work through expanded JSON strings transparently.
103
+
104
+ ### Live Tailing
105
+
106
+ With `--follow`, jnav watches the file for new lines (like `tail -f`). New entries are parsed, filtered, and appended to the view. If you're at the bottom of the list, it auto-scrolls to show new entries.
107
+
108
+ ### Session Persistence
109
+
110
+ Filters, selected fields, scroll position, panel state, and search terms are saved when you quit and restored when reopening the same file. State is stored in `~/.local/share/jnav/`.
111
+
112
+ ## Keybindings
113
+
114
+ ### Navigation
115
+
116
+ | Key | Action |
117
+ | ------------------- | --------------------------- |
118
+ | `j` / `k` | Move up/down |
119
+ | `gg` / `G` | Jump to first/last entry |
120
+ | `Ctrl+D` / `Ctrl+U` | Half-page scroll |
121
+ | `h` / `l` | Focus list / detail panel |
122
+ | `Enter` | Inspect entry (open detail) |
123
+ | `Escape` | Back |
124
+
125
+ ### Search and Filter
126
+
127
+ | Key | Action |
128
+ | --------- | -------------------------------------------------- |
129
+ | `/` | Search (highlights matches, does not hide entries) |
130
+ | `n` / `N` | Next / previous search match |
131
+ | `F` | Filter manager (jq expressions) |
132
+ | `ft` | Quick text filter |
133
+ | `fp` | Pause / resume filters |
134
+ | `Escape` | Clear search |
135
+ | `r` | Reset filters, fields, and search |
136
+
137
+ ### Display
138
+
139
+ | Key | Action |
140
+ | ---- | ---------------------------------------- |
141
+ | `S` | Selected fields manager |
142
+ | `vi` | Toggle inline expanded tree in list rows |
143
+ | `d` | Toggle detail panel |
144
+ | `?` | Help |
145
+ | `q` | Quit |
146
+
147
+ ### Detail Panel
148
+
149
+ | Key | Action |
150
+ | ---- | ---------------------------------------- |
151
+ | `s` | Select (or deselect) the field |
152
+ | `ff` | Filter by value of the highlighted field |
153
+ | `fn` | Filter: entries that have this field |
154
+ | `ve` | View the value in `$EDITOR` |
155
+ | `vo` | Show only selected fields |
156
+
157
+ ### Filter Manager
158
+
159
+ | Key | Action |
160
+ | --------------- | -------------------------- |
161
+ | `a` | Add filter clause |
162
+ | `g` | Add group |
163
+ | `e` | Edit clause |
164
+ | `d` / `y` / `p` | Cut / yank / paste |
165
+ | `t` | Enable / disable |
166
+ | `o` | Toggle AND / OR on a group |
167
+ | `n` | Negate |
168
+ | `c` | Flatten group |
169
+ | `r` | Rename |
170
+ | `Escape` | Close |
171
+
172
+ ### Selected Fields Manager
173
+
174
+ | Key | Action |
175
+ | --------------- | ------------------ |
176
+ | `a` | Add selector |
177
+ | `e` | Edit selector |
178
+ | `d` / `y` / `p` | Cut / yank / paste |
179
+ | `t` | Enable / disable |
180
+ | `Escape` | Close |
181
+
182
+ ## Credits
183
+
184
+ - [lnav](https://github.com/tstack/lnav): the main inspiration: an interactive log viewer with structured querying
185
+ - [hl](https://github.com/pamburus/hl): shaped several design decisions around how JSON log entries should look
186
+ - [Open Color](https://yeun.github.io/open-color/): the palette the theme is built on
@@ -0,0 +1,37 @@
1
+ jnav/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ jnav/__main__.py,sha256=QOQsLe1gcri1Uxj4wzsWVzAdE5g2qqr0gDajClfHLa8,2966
3
+ jnav/app.py,sha256=c5mE71O7WI9rX2MUoErDwtYL_a0EeyBcl6MYjd4rFU0,13765
4
+ jnav/buffer.py,sha256=K4Mv970YDb3qmvSARLIGoRPnx75BIJN9f22B7bK8Bko,1673
5
+ jnav/detail_tree.py,sha256=Oi6dl7QPUIM13b8DB9gZOzpfUUlI7cEhOVPjeedg-Zo,7956
6
+ jnav/field_mapping.py,sha256=CO3IXGH5NtbjOimKKWtCbZaGLmR_MlAagDIkKWWRG-Y,3603
7
+ jnav/filter_manager_screen.py,sha256=rs-voeCvsngD4b39zRelWGPOoIlJGV5JAuc_me6umHs,2792
8
+ jnav/filter_provider.py,sha256=3xqBhQVS0yma72ic6dubBU_ZMgKbdCPz6kXNksPJa4Q,3350
9
+ jnav/filter_tree.py,sha256=J-vYfTyphD0gD4vLusBp-5xeasRxf3QJ1yHOIbuR1Bc,11157
10
+ jnav/filtering.py,sha256=vBehFDHOdJGrO3wGNqfZ3solnDv05PJwP2Nyw3iwN0k,5586
11
+ jnav/header.py,sha256=yHWOlZMUPNND03Pm4EzcgrDewNna2US9zy04_y1n3f0,1166
12
+ jnav/help_screen.py,sha256=kfHROpgxUmDxfftKGNhoA9rHceCgAmByqE4x34INBBM,2155
13
+ jnav/inline_tree.py,sha256=0-7zRLIgGSF6yOeNpruOZOHQT3nZIhmcZNLQbk60zhc,2055
14
+ jnav/key_sequences.py,sha256=1NL0LbKyyg8URxPVCC1-GT6JZbK0d58ARKiIh2SMtu4,7506
15
+ jnav/log_entry_item.py,sha256=XjJMnC-FlsxxBJ0fZbRDIHWTGmiXJMEY8POkKSTeSGI,3187
16
+ jnav/log_entry_renderer.py,sha256=gcgNvG0SaFRdSOBaOqhgNtV_bc7_zqg2fyTCEcylUi8,2595
17
+ jnav/log_list_view.py,sha256=FVUKTlhRNDp9v7FNFH1HdZFXZHsKpJbc5FSwVeJT7NE,10443
18
+ jnav/log_model.py,sha256=CLHfGwdTApDEm2huBCeSlc5ZGVYkUhRFZsV5n3uQjrQ,3616
19
+ jnav/logging.py,sha256=yHyciDTaExPgzYY98NeIH1JeyBBfZvCk3IvPsJeK6Js,1531
20
+ jnav/manager_screen_common.py,sha256=2NLx7KxB_Uc40HW0l0N2Wmw-ukcTFbHnKKCXzQK2d8o,775
21
+ jnav/model.py,sha256=LNqYL6C6Mba8s938734eGQ802_7GqVXMS5iPUY3KYX8,316
22
+ jnav/offset_group.py,sha256=GhafG2IF5sPXqBvsHGvq_RLBuJfXC42NVRxX8_2pF2U,926
23
+ jnav/parsing.py,sha256=e7BPwst-WKVAsKPxxUQyHdf-kw7vzBwWo5ItzaMQ8zU,2882
24
+ jnav/reading.py,sha256=_GYsENtilHN2k99Gcx7T6iCViHRK7BsivmiPxs1vSEg,1554
25
+ jnav/role_mapper.py,sha256=KXuTvb0t-184HtU1TZ1tG_kp04MNic7RlhlzinyIs_w,1714
26
+ jnav/scrollbar_overlay.py,sha256=9ZB1zKun_0wq2HSj-SffCDmVUhtHbWnIXjNdNSKeiKs,2735
27
+ jnav/search_engine.py,sha256=q7zcvgO8mBrGTGOw9hfnBaEFA7p-YPAR1_wDdOCbqoM,2505
28
+ jnav/selector_manager_screen.py,sha256=fWlWQS_0PwuvuTLJuyTjcFeYwUW2_l09PkjQBp03xIw,6053
29
+ jnav/selector_provider.py,sha256=Y4vSi1VF1VQFB0RCiNZZmefSFcagljulxnd7HN_XP1w,2065
30
+ jnav/store.py,sha256=v2bGRTF-Cza1n-FqlujDKu23pykDVKUcjIPD07feIDE,982
31
+ jnav/text_input_screen.py,sha256=0Qfdaq-iOzBdkyBNI5FmQfmbQI5a9Y52zt_Qex5T_0Y,1693
32
+ jnav/tree_rendering.py,sha256=B7Ql99Q4IDjKECSzHUsac4BpnAa3azN7o89utfRA7-s,6515
33
+ jnav/virtual_list_view.py,sha256=3ZBbeuLeRU-07aymn4HMnND_nI5nCeqfWNFQkgnfCSQ,12568
34
+ jnav-1.0.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
35
+ jnav-1.0.0.dist-info/entry_points.txt,sha256=iKyF9p2eMdUVndwBC7RLIReTlIC9xG7M5ySMbsUdHQk,45
36
+ jnav-1.0.0.dist-info/METADATA,sha256=NnSibuis_IcOShNhexuMSPF42W6RDOf3POnAIutnJ9M,7276
37
+ jnav-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.8.24
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ jnav = jnav.__main__:main
3
+