docker-orb 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.
- docker_orb/__init__.py +0 -0
- docker_orb/__main__.py +5 -0
- docker_orb/_scrollbar.py +136 -0
- docker_orb/cli.py +167 -0
- docker_orb/colors.py +60 -0
- docker_orb/compose.py +391 -0
- docker_orb/config.py +244 -0
- docker_orb/inject.py +160 -0
- docker_orb/jsonlog.py +125 -0
- docker_orb/models.py +132 -0
- docker_orb/viewer/__init__.py +0 -0
- docker_orb/viewer/app.py +824 -0
- docker_orb/viewer/panels/__init__.py +0 -0
- docker_orb/viewer/panels/health.py +239 -0
- docker_orb/viewer/panels/main_stream.py +389 -0
- docker_orb/viewer/panels/monitor.py +233 -0
- docker_orb/viewer/panels/search.py +182 -0
- docker_orb/viewer/viewer.tcss +205 -0
- docker_orb/viewer/widgets.py +668 -0
- docker_orb/wizard/__init__.py +0 -0
- docker_orb/wizard/app.py +40 -0
- docker_orb/wizard/screens.py +692 -0
- docker_orb/wizard/wizard.tcss +329 -0
- docker_orb-1.0.0.dist-info/METADATA +192 -0
- docker_orb-1.0.0.dist-info/RECORD +28 -0
- docker_orb-1.0.0.dist-info/WHEEL +4 -0
- docker_orb-1.0.0.dist-info/entry_points.txt +3 -0
- docker_orb-1.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/* ── Overall layout ──────────────────────────────────────────────────────── */
|
|
2
|
+
|
|
3
|
+
Screen {
|
|
4
|
+
background: $surface;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
#wizard-title {
|
|
8
|
+
text-align: center;
|
|
9
|
+
text-style: bold;
|
|
10
|
+
color: $accent;
|
|
11
|
+
background: $panel;
|
|
12
|
+
padding: 1 0;
|
|
13
|
+
border-bottom: solid $accent;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#wizard-footer {
|
|
17
|
+
text-align: center;
|
|
18
|
+
color: $text-muted;
|
|
19
|
+
background: $panel;
|
|
20
|
+
padding: 0 1;
|
|
21
|
+
border-top: solid $panel-lighten-2;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
TabbedContent {
|
|
25
|
+
height: 1fr;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
TabPane {
|
|
29
|
+
padding: 1 2;
|
|
30
|
+
height: 1fr;
|
|
31
|
+
layout: vertical;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#targets-scroll, #strings-scroll, #options-scroll {
|
|
35
|
+
height: 1fr;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* ── Section headers ─────────────────────────────────────────────────────── */
|
|
39
|
+
|
|
40
|
+
.section-title {
|
|
41
|
+
text-style: bold;
|
|
42
|
+
color: $accent;
|
|
43
|
+
padding: 1 0 1 2;
|
|
44
|
+
border-left: outer $accent;
|
|
45
|
+
background: $panel;
|
|
46
|
+
margin-top: 1;
|
|
47
|
+
margin-bottom: 1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* ── Labels and hints ────────────────────────────────────────────────────── */
|
|
51
|
+
|
|
52
|
+
.field-label {
|
|
53
|
+
color: $text-muted;
|
|
54
|
+
margin-bottom: 0;
|
|
55
|
+
padding-left: 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.field-hint {
|
|
59
|
+
color: $text-muted;
|
|
60
|
+
padding-left: 1;
|
|
61
|
+
margin-bottom: 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.field-warn {
|
|
65
|
+
color: $warning;
|
|
66
|
+
padding-left: 1;
|
|
67
|
+
margin: 1 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ── Rules ───────────────────────────────────────────────────────────────── */
|
|
71
|
+
|
|
72
|
+
Rule {
|
|
73
|
+
margin: 1 0;
|
|
74
|
+
color: $panel-lighten-2;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* ── Rows ────────────────────────────────────────────────────────────────── */
|
|
78
|
+
|
|
79
|
+
.row {
|
|
80
|
+
height: auto;
|
|
81
|
+
margin-bottom: 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.row Button {
|
|
85
|
+
margin-right: 1;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* ── Inputs — bright border to stand out ─────────────────────────────────── */
|
|
89
|
+
|
|
90
|
+
Input {
|
|
91
|
+
background: $panel;
|
|
92
|
+
border: tall $primary-lighten-2;
|
|
93
|
+
margin-bottom: 1;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
Input:focus {
|
|
97
|
+
border: tall $accent;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* ── Select ──────────────────────────────────────────────────────────────── */
|
|
101
|
+
|
|
102
|
+
Select {
|
|
103
|
+
margin-bottom: 1;
|
|
104
|
+
width: auto;
|
|
105
|
+
max-width: 60;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Namespace select sits in a row with a button — let it grow to fill */
|
|
109
|
+
#ns-select {
|
|
110
|
+
width: 1fr;
|
|
111
|
+
max-width: 60;
|
|
112
|
+
margin-bottom: 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
Select > SelectCurrent {
|
|
116
|
+
background: $panel;
|
|
117
|
+
border: tall $primary-lighten-2;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Select:focus > SelectCurrent {
|
|
121
|
+
border: tall $accent;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ── Namespace ───────────────────────────────────────────────────────────── */
|
|
125
|
+
|
|
126
|
+
#ns-select {
|
|
127
|
+
margin-bottom: 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#ns-input {
|
|
131
|
+
width: 1fr;
|
|
132
|
+
max-width: 60;
|
|
133
|
+
margin-bottom: 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
/* ── Saved config select ─────────────────────────────────────────────────── */
|
|
138
|
+
|
|
139
|
+
#cfg-select {
|
|
140
|
+
width: 1fr;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* ── Deployment list ─────────────────────────────────────────────────────── */
|
|
144
|
+
|
|
145
|
+
.btn-small {
|
|
146
|
+
min-width: 12;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
#dep-scroll {
|
|
150
|
+
height: 7;
|
|
151
|
+
width: 64;
|
|
152
|
+
background: $panel;
|
|
153
|
+
border: tall $primary-lighten-2;
|
|
154
|
+
margin-bottom: 0;
|
|
155
|
+
scrollbar-size-vertical: 2;
|
|
156
|
+
scrollbar-color: $accent;
|
|
157
|
+
scrollbar-color-hover: $accent-lighten-1;
|
|
158
|
+
scrollbar-background: $panel-darken-1;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#dep-checks {
|
|
162
|
+
height: auto;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* ── Checkboxes ──────────────────────────────────────────────────────────── */
|
|
166
|
+
|
|
167
|
+
Checkbox {
|
|
168
|
+
height: auto;
|
|
169
|
+
margin: 0;
|
|
170
|
+
padding: 0 1;
|
|
171
|
+
background: transparent;
|
|
172
|
+
border: none;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
Checkbox > .toggle--button {
|
|
176
|
+
color: $panel;
|
|
177
|
+
background: $panel-darken-1;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
Checkbox.-on > .toggle--button {
|
|
181
|
+
color: $text;
|
|
182
|
+
background: $success;
|
|
183
|
+
text-style: bold;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
Checkbox:focus {
|
|
187
|
+
background: $panel-lighten-1;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
Checkbox:hover {
|
|
191
|
+
background: $panel-lighten-1;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* ── RadioSet ────────────────────────────────────────────────────────────── */
|
|
195
|
+
|
|
196
|
+
RadioSet {
|
|
197
|
+
background: $panel;
|
|
198
|
+
border: tall $primary-lighten-2;
|
|
199
|
+
padding: 0 1;
|
|
200
|
+
height: auto;
|
|
201
|
+
width: 48;
|
|
202
|
+
margin-bottom: 1;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
RadioButton {
|
|
206
|
+
background: transparent;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* ── Dump options ────────────────────────────────────────────────────────── */
|
|
210
|
+
|
|
211
|
+
#dump-opts {
|
|
212
|
+
padding: 0 0 0 2;
|
|
213
|
+
margin-top: 0;
|
|
214
|
+
margin-bottom: 1;
|
|
215
|
+
height: auto;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
#dump-tail, #dump-since {
|
|
219
|
+
width: 24;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* ── Stream options ───────────────────────────────────────────────────────── */
|
|
223
|
+
|
|
224
|
+
#stream-opts {
|
|
225
|
+
padding: 0 0 0 2;
|
|
226
|
+
margin-top: 0;
|
|
227
|
+
margin-bottom: 1;
|
|
228
|
+
height: auto;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
#stream-since {
|
|
232
|
+
width: 40;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* ── Patterns edit row ───────────────────────────────────────────────────── */
|
|
236
|
+
|
|
237
|
+
#patterns-edit-row {
|
|
238
|
+
align: left middle;
|
|
239
|
+
height: auto;
|
|
240
|
+
margin-bottom: 0;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#patterns-file-hint {
|
|
244
|
+
width: 1fr;
|
|
245
|
+
margin-bottom: 0;
|
|
246
|
+
padding-left: 1;
|
|
247
|
+
color: $text-muted;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* ── String check lists ──────────────────────────────────────────────────── */
|
|
251
|
+
|
|
252
|
+
#filter-scroll, #hl-scroll, #mon-scroll {
|
|
253
|
+
height: 7;
|
|
254
|
+
width: 64;
|
|
255
|
+
background: $panel;
|
|
256
|
+
border: tall $primary-lighten-2;
|
|
257
|
+
margin-bottom: 0;
|
|
258
|
+
scrollbar-size-vertical: 2;
|
|
259
|
+
scrollbar-color: $accent;
|
|
260
|
+
scrollbar-color-hover: $accent-lighten-1;
|
|
261
|
+
scrollbar-background: $panel-darken-1;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
#filter-checks, #hl-checks, #mon-checks {
|
|
265
|
+
height: auto;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* Dim label above saved list to distinguish from the "Add new" input below */
|
|
269
|
+
.saved-label {
|
|
270
|
+
color: $text-muted;
|
|
271
|
+
padding-left: 1;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* Accent the "Add new" label so it reads as a distinct action area */
|
|
275
|
+
.new-label {
|
|
276
|
+
color: $accent;
|
|
277
|
+
padding-left: 1;
|
|
278
|
+
margin-top: 1;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.option-row {
|
|
282
|
+
height: auto;
|
|
283
|
+
margin-top: 0;
|
|
284
|
+
margin-bottom: 1;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.option-row Checkbox {
|
|
288
|
+
width: 1fr;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* ── Health options ──────────────────────────────────────────────────────── */
|
|
292
|
+
|
|
293
|
+
#health-opts {
|
|
294
|
+
padding: 0 0 0 2;
|
|
295
|
+
height: auto;
|
|
296
|
+
margin-top: 0;
|
|
297
|
+
margin-left: 0;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
#health-interval {
|
|
301
|
+
width: 16;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
#health-section, #monitor-section {
|
|
305
|
+
height: auto;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/* ── Options tab ─────────────────────────────────────────────────────────── */
|
|
309
|
+
|
|
310
|
+
#save-name {
|
|
311
|
+
margin-bottom: 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.nav-row {
|
|
315
|
+
margin-top: 1;
|
|
316
|
+
height: auto;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.btn-cancel {
|
|
320
|
+
width: 1fr;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.btn-back {
|
|
324
|
+
width: 1fr;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.btn-next {
|
|
328
|
+
width: 3fr;
|
|
329
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: docker-orb
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Interactive terminal UI for streaming and filtering Docker Compose container logs across multiple services
|
|
5
|
+
Project-URL: Homepage, https://github.com/adlidev/docker-orb
|
|
6
|
+
Project-URL: Repository, https://github.com/adlidev/docker-orb
|
|
7
|
+
Project-URL: Documentation, https://github.com/adlidev/docker-orb/blob/main/docs/USER_GUIDE.md
|
|
8
|
+
Project-URL: Issues, https://github.com/adlidev/docker-orb/issues
|
|
9
|
+
Author-email: Adli Waziri <boulderadli@gmail.com>
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 Adli Waziri
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: compose,devops,docker,docker-compose,logs,observability,sre,textual,tui
|
|
33
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
34
|
+
Classifier: Environment :: Console
|
|
35
|
+
Classifier: Intended Audience :: Developers
|
|
36
|
+
Classifier: Intended Audience :: System Administrators
|
|
37
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
38
|
+
Classifier: Operating System :: MacOS
|
|
39
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
40
|
+
Classifier: Programming Language :: Python :: 3
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
44
|
+
Classifier: Topic :: System :: Logging
|
|
45
|
+
Classifier: Topic :: System :: Monitoring
|
|
46
|
+
Classifier: Topic :: System :: Systems Administration
|
|
47
|
+
Classifier: Topic :: Utilities
|
|
48
|
+
Requires-Python: >=3.10
|
|
49
|
+
Requires-Dist: click>=8.1
|
|
50
|
+
Requires-Dist: pyyaml>=6.0
|
|
51
|
+
Requires-Dist: textual>=0.61.0
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
53
|
+
|
|
54
|
+
# docker-orb
|
|
55
|
+
|
|
56
|
+
Watching logs across a multi-container Compose stack usually means juggling
|
|
57
|
+
multiple `docker compose logs` windows and grepping after the fact, or
|
|
58
|
+
writing complex regex just to add a couple of filters. docker-orb streams
|
|
59
|
+
logs from every container in your selected services into one merged,
|
|
60
|
+
colorized view — and lets you filter, highlight, and search *while it's
|
|
61
|
+
streaming*.
|
|
62
|
+
|
|
63
|
+
Built with [Textual](https://textual.textualize.io/), docker-orb is a full
|
|
64
|
+
terminal UI: an interactive setup wizard walks you through picking a
|
|
65
|
+
project, services, and filter patterns — no flags required — or skip
|
|
66
|
+
straight to the viewer with CLI arguments if you prefer. Save named session
|
|
67
|
+
configs to reload your exact setup later; passively collect rare events in
|
|
68
|
+
a monitor panel without losing your scroll position; get alerted when
|
|
69
|
+
containers restart or go unhealthy; and add or remove services from the
|
|
70
|
+
live stream without restarting.
|
|
71
|
+
|
|
72
|
+

|
|
73
|
+
|
|
74
|
+
## Features
|
|
75
|
+
|
|
76
|
+
- **Multi-container live tail** — stream logs from any number of
|
|
77
|
+
containers/services at once, each with a distinct color.
|
|
78
|
+
- **Filters** — hide lines matching a pattern, live-editable mid-session.
|
|
79
|
+
- **Highlights** — emphasize lines matching a pattern without hiding anything else.
|
|
80
|
+
- **Monitors** — passively collect matching lines into a separate panel so you
|
|
81
|
+
can watch for rare events (e.g. `job failed`) without losing your scroll
|
|
82
|
+
position in the main stream.
|
|
83
|
+
- **Live search** — search the whole buffered session, jump to a result, and
|
|
84
|
+
keep streaming.
|
|
85
|
+
- **Container health panel** — flags containers that aren't `Running` or have
|
|
86
|
+
crossed a restart threshold; restart a container or recreate a service from
|
|
87
|
+
inside the app.
|
|
88
|
+
- **Dump mode** — fetch existing logs once (with `--tail`/`--since`) and exit,
|
|
89
|
+
for scripting or one-off inspection, instead of a live stream.
|
|
90
|
+
- **Saved configs** — save a named combination of project, services, and
|
|
91
|
+
patterns, and reload it later by name.
|
|
92
|
+
- **JSON log formatting** — auto-detects structured JSON log lines and shows
|
|
93
|
+
`time LEVEL message key=value ...` instead of a raw JSON blob, with a
|
|
94
|
+
toggle back to raw and a detail view (Enter on a clicked line) for the full
|
|
95
|
+
pretty-printed object.
|
|
96
|
+
- **Collapse repeated lines** — journalctl-style: consecutive identical lines
|
|
97
|
+
from the same container fold into a single "last line repeated N times"
|
|
98
|
+
marker, toggleable, so a crash-looping container doesn't flood the stream.
|
|
99
|
+
|
|
100
|
+
## Installation
|
|
101
|
+
|
|
102
|
+
Requires Python 3.10+, and `docker` with the Compose v2 plugin on your
|
|
103
|
+
`PATH` (i.e. `docker compose` works). docker-orb shells out to your existing
|
|
104
|
+
`docker` CLI and inherits its context/auth — no separate credentials or
|
|
105
|
+
Docker SDK involved.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Recommended — pipx keeps CLI tools in isolated environments. Not on PyPI
|
|
109
|
+
# yet, so install straight from GitHub:
|
|
110
|
+
pipx install git+https://github.com/adlidev/docker-orb
|
|
111
|
+
|
|
112
|
+
# Or with plain pip, inside your own venv:
|
|
113
|
+
git clone https://github.com/adlidev/docker-orb.git
|
|
114
|
+
cd docker-orb
|
|
115
|
+
pip install -e .
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This installs two commands: `docker-orb` and `docker-orb-inject` (a small
|
|
119
|
+
test utility for injecting fake log lines into a running container — see
|
|
120
|
+
the [User Guide](docs/USER_GUIDE.md#docker-orb-inject)).
|
|
121
|
+
|
|
122
|
+
**For development / contributing:**
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
git clone https://github.com/adlidev/docker-orb.git
|
|
126
|
+
cd docker-orb
|
|
127
|
+
pip install -e . --group dev
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Quick start
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# No arguments — launches the interactive setup wizard
|
|
134
|
+
docker-orb
|
|
135
|
+
|
|
136
|
+
# Skip the wizard: watch two services live
|
|
137
|
+
docker-orb -n myapp -p api -p worker
|
|
138
|
+
|
|
139
|
+
# Watch every service in a project
|
|
140
|
+
docker-orb -n myapp --all-containers
|
|
141
|
+
|
|
142
|
+
# One-shot dump instead of a live stream
|
|
143
|
+
docker-orb -n myapp --dump --tail 500
|
|
144
|
+
|
|
145
|
+
# Pre-filter/highlight from the command line
|
|
146
|
+
docker-orb -n myapp -p worker -f DEBUG -H ERROR --health
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`-n/--project` takes the Compose project name (what `docker compose -p`
|
|
150
|
+
expects — usually the directory name your `docker-compose.yml` lives in,
|
|
151
|
+
unless overridden by a top-level `name:` key or `COMPOSE_PROJECT_NAME`). If
|
|
152
|
+
omitted, docker-orb resolves it the same way `docker compose` does for the
|
|
153
|
+
current directory.
|
|
154
|
+
|
|
155
|
+
Once you're in the viewer, press `F` / `H` / `M` to edit filters, highlights,
|
|
156
|
+
or monitors live, `/` to search, `P` to add/remove streamed services, and
|
|
157
|
+
`Space` to pause. See the [User Guide](docs/USER_GUIDE.md) for the full
|
|
158
|
+
keybinding reference and pattern syntax.
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
pip install -e . --group dev
|
|
164
|
+
pytest # run the test suite
|
|
165
|
+
textual run --dev src/docker_orb/__main__.py # live-reload dev mode
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
A local Compose stack with 8 fake log-generating services is included for
|
|
169
|
+
manual testing:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
cd infra
|
|
173
|
+
make up
|
|
174
|
+
docker-orb -n logviewer-demo --all-containers --health
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
See [`infra/README.md`](infra/README.md) for the service list and good
|
|
178
|
+
filter/monitor test patterns, and [`CLAUDE.md`](CLAUDE.md) for architecture
|
|
179
|
+
notes.
|
|
180
|
+
|
|
181
|
+
## Relationship to kube-orb
|
|
182
|
+
|
|
183
|
+
docker-orb is a sibling project to [kube-orb](https://github.com/adlidev/kube-orb),
|
|
184
|
+
Adli's Kubernetes-flavored log viewer. They share a UI architecture (Textual
|
|
185
|
+
viewer, wizard, filters/highlights/monitors, JSON formatting) but each talks
|
|
186
|
+
to its own backend directly — docker-orb shells out to `docker`/`docker
|
|
187
|
+
compose`, kube-orb shells out to `kubectl` — and they're maintained as
|
|
188
|
+
independent tools rather than one project trying to do both.
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
[MIT License](LICENSE)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
docker_orb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
docker_orb/__main__.py,sha256=yq_aInmV6HCZN0Hl1TpmfBSErrRJNtSisb8tTfqi_8E,140
|
|
3
|
+
docker_orb/_scrollbar.py,sha256=U_1BiB70LJMpWXQnlkj25AAzNKEe5kqtzWoZhmYK34s,5344
|
|
4
|
+
docker_orb/cli.py,sha256=mEYpwLVNoKAW-LtYnhm3eu57nNA_reLizZJ1t0AHJJ8,7390
|
|
5
|
+
docker_orb/colors.py,sha256=Ufe21cwg3nToiILeTshU5g1FWjfYkIT6cQmzvGa_3n4,2109
|
|
6
|
+
docker_orb/compose.py,sha256=8ClUrO632V4N2_uIfZRSgHhUKFTo671_NTxqEeDD2eg,14659
|
|
7
|
+
docker_orb/config.py,sha256=V6DZOapozTvC4n0PQXcko9uennzeEwq1ehV0mrtlnNg,8766
|
|
8
|
+
docker_orb/inject.py,sha256=or0M8_hy_pDChCfK_zlT10kZcBys6pmkvTjzO-1O2X4,5714
|
|
9
|
+
docker_orb/jsonlog.py,sha256=134VJrKseHksLKD2_yNxisYFcrPuRdE9lTydaAsc_2Q,4627
|
|
10
|
+
docker_orb/models.py,sha256=qxrd8Y7nMKzWT60nkjB6liiplpZT9xi8wRZT7rAJW3M,4807
|
|
11
|
+
docker_orb/viewer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
docker_orb/viewer/app.py,sha256=8rXamUBqDEFOqrFsAMxNDWa9pjIIOWrhNULBAIgArX0,37356
|
|
13
|
+
docker_orb/viewer/viewer.tcss,sha256=D87cfT-3ilimIysNurvlmTPPGb02DvxPelmC4OEkcf0,4554
|
|
14
|
+
docker_orb/viewer/widgets.py,sha256=4CXxlm7mO5dq7qUfx3VyAKdxJ-xXl3ydmjKwzgH7ruM,23322
|
|
15
|
+
docker_orb/viewer/panels/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
docker_orb/viewer/panels/health.py,sha256=oB_jPVP5KskTfOUQB6TX_x2SdswagZkk0rFZJBu7Zhs,8897
|
|
17
|
+
docker_orb/viewer/panels/main_stream.py,sha256=Lz2Vno9Ac9i7sRH07mmITVD_kEibS_cYFAvg9m1tir8,15740
|
|
18
|
+
docker_orb/viewer/panels/monitor.py,sha256=2S5gWReXC5lK1djRDGcrIgYpoTD8eVY-PRCqMV2xS38,7990
|
|
19
|
+
docker_orb/viewer/panels/search.py,sha256=0pRqLmAoTtgawAfQNBkWqNEqsxbVScA-YeWRMY2VMK8,6192
|
|
20
|
+
docker_orb/wizard/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
docker_orb/wizard/app.py,sha256=XPqo74kjz7VWevCKW3jKfFVWjXQz48vIBnUsKcCkrD0,986
|
|
22
|
+
docker_orb/wizard/screens.py,sha256=n4ss7YvLGRHM7Ft779faQy7AXQy_Ofwfop4GlSMp37s,32838
|
|
23
|
+
docker_orb/wizard/wizard.tcss,sha256=i7tRSWti7Vqjdmp6azmC2AMkdQRsjoyCBRRPfxeGVGs,7908
|
|
24
|
+
docker_orb-1.0.0.dist-info/METADATA,sha256=UfdiGXQjfQKE37hoyV8kvGd66dVgOhpdp-XT8cJn83s,8144
|
|
25
|
+
docker_orb-1.0.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
26
|
+
docker_orb-1.0.0.dist-info/entry_points.txt,sha256=KxDwYM0UTmOb9mhhvQbhc9cOMofb0vJkZ3yPRe9hNmA,94
|
|
27
|
+
docker_orb-1.0.0.dist-info/licenses/LICENSE,sha256=zVfZOlwrrTMcNn4XNJED1CoLkon34cOGUn6R-mtqf04,1068
|
|
28
|
+
docker_orb-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Adli Waziri
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|