Skip to content

Commit 6ae1d09

Browse files
committed
Support expand log item
1 parent 4d8898a commit 6ae1d09

File tree

4 files changed

+94
-49
lines changed

4 files changed

+94
-49
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ Run your application then check the http://127.0.0.1:3000 to see the tracing dat
8484

8585
- [x] Support tracing diagnosing with Jaeger UI.
8686

87-
- [ ] Build duo web UI.
87+
- [x] Build duo web UI.
8888

89-
- [ ] Support logging diagnosing.
89+
- [x] Support logging diagnosing.
9090

9191
- [x] Support arrow-ipc WAL.
9292

duo-subscriber/examples/main.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ use std::time::Duration;
22

33
use duo_subscriber::DuoLayer;
44
use tonic::transport::Uri;
5-
use tracing::{debug, error, Level};
5+
use tracing::{debug, error, info, warn, Level};
66
use tracing_subscriber::{
77
self, filter::Targets, fmt, layer::SubscriberExt, util::SubscriberInitExt,
88
};
99

1010
#[tracing::instrument]
1111
fn foo() {
12-
debug!(test = true, "hello foo!");
12+
info!(test = true, "hello foo!");
1313
bar();
1414
debug!("called bar!");
1515
foz();
@@ -22,7 +22,7 @@ fn bar() {
2222

2323
#[tracing::instrument]
2424
fn baz() {
25-
debug!("hello baz!");
25+
warn!("hello baz!");
2626
}
2727

2828
#[tracing::instrument]
@@ -46,7 +46,7 @@ async fn main() {
4646
)
4747
.init();
4848

49-
tracing::debug!("Bootstrap...");
49+
tracing::info!("Bootstrap...");
5050
foo();
5151
tokio::time::sleep(Duration::from_secs(1)).await;
5252
}

duo-ui/src/lib/components/LogItem.svelte

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,71 @@
3939
* @type {number}
4040
*/
4141
export let time;
42+
let expand = false;
43+
let levelColor = 'white';
44+
45+
$: {
46+
switch (level.toLowerCase()) {
47+
case 'info':
48+
levelColor = '#206ce8';
49+
break;
50+
case 'warn':
51+
levelColor = '#ff9c00';
52+
break;
53+
case 'error':
54+
levelColor = '#f55555';
55+
break;
56+
case 'debug':
57+
default:
58+
levelColor = '#47474a';
59+
break;
60+
}
61+
}
62+
63+
function allFields() {
64+
return {
65+
message,
66+
process_id,
67+
trace_id,
68+
span_id,
69+
level,
70+
target,
71+
file: `${file}:${line}`,
72+
time: dayjs(time / 1000).format('YYYY-MM-DD HH:mm:ss.SSS'),
73+
...$$restProps
74+
};
75+
}
4276
</script>
4377

44-
<div class="text-md mx-4 my-2 flex flex-row">
78+
<button
79+
class="text-md flex w-full flex-row px-4 py-2 text-sm text-slate-600 hover:cursor-pointer"
80+
on:click={() => (expand = !expand)}
81+
>
4582
<div class="flex grow flex-row flex-wrap">
46-
<div class="mx-2">{level}</div>
47-
<div class="mx-2">{dayjs(time / 1000).format('YYYY-MM-DD HH:mm:ss.SSS')}</div>
48-
<div class="mx-2">{message}</div>
83+
<div class="text-slate-500">{dayjs(time / 1000).format('YYYY-MM-DD HH:mm:ss.SSS')}</div>
84+
<div class="flex" style:color={levelColor}>
85+
<div class="mx-2 w-10"><code>{level}</code></div>
86+
<div class="mx-2">{message}</div>
87+
</div>
4988
{#if $$restProps}
5089
{#each Object.entries($$restProps) as [key, value]}
5190
<div class="mx-2">
52-
<span>{key}</span>:<span>{value}</span>
91+
<span class="mr-1 rounded-sm bg-slate-100 px-2 py-1">{key}:</span><span>{value}</span>
5392
</div>
5493
{/each}
5594
{/if}
5695
</div>
57-
<Badge class="flex self-end" variant="outline">{process_id}</Badge>
58-
</div>
96+
<Badge class="flex items-center self-end" variant="outline">{process_id}</Badge>
97+
</button>
5998
<Separator />
99+
{#if expand}
100+
<div class="p-4">
101+
{#each Object.entries(allFields()) as [key, value]}
102+
<div class="grid grid-cols-8 gap-4 text-sm text-slate-500">
103+
<code class="col-span-1 text-end">{key}</code>
104+
<div class="col-span-7">{value || ''}</div>
105+
</div>
106+
<Separator />
107+
{/each}
108+
</div>
109+
{/if}

duo-ui/src/routes/+page.svelte

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,11 @@
9696
return params;
9797
}
9898
99-
async function onSearch() {
99+
async function search() {
100100
let params = queryParams();
101101
let response = await fetch(`http://localhost:3000/api/logs?${params.toString()}`);
102102
if (response.ok) {
103-
logs = [...logs, ...(await response.json())];
103+
logs = await response.json();
104104
}
105105
}
106106
@@ -119,9 +119,7 @@
119119
items = await response.json();
120120
for (let item of items) {
121121
total += item.count;
122-
if (item.count > max) {
123-
max = item.count;
124-
}
122+
max = Math.max(max, item.count);
125123
}
126124
}
127125
return {
@@ -135,7 +133,7 @@
135133
if (data.services && data.services.length > 0) {
136134
currentSevice = data.services[0];
137135
}
138-
console.log(data);
136+
await search();
139137
});
140138
</script>
141139

@@ -148,6 +146,7 @@
148146
searchable={false}
149147
resetOnBlur={false}
150148
bind:value={currentSevice}
149+
on:change={search}
151150
></Svelecte>
152151
<Input class="mx-4 max-w-screen-md" placeholder="Search log by keyword" bind:value={keyword} />
153152
<div class="mx-6">
@@ -177,46 +176,42 @@
177176
</Button>
178177
</DatePicker>
179178
</div>
180-
<Button on:click={onSearch}>Search</Button>
179+
<Button on:click={search}>Search</Button>
181180
</div>
182181
<Separator class="my-8" />
183182
<Resizable.PaneGroup direction="horizontal" class="rounded-lg border py-2">
184-
<Resizable.Pane defaultSize={18}>
185-
<h2 class="px-4 text-center text-lg font-bold">Fields</h2>
183+
<Resizable.Pane defaultSize={18} minSize={12} maxSize={24}>
184+
<h2 class="px-4 py-2 text-center text-lg font-bold">Fields</h2>
186185
{#each filterableFields() as field}
187-
<Collapsible.Root class="space-y-2 text-sm">
188-
<div class="space-x-4 px-4">
189-
<Collapsible.Trigger class="w-full">
190-
<div class="flex items-center py-1 text-slate-500 hover:bg-gray-100">
191-
<code class="flex grow">
192-
{field.name}
193-
</code>
194-
<Datatype type={field.data_type} />
195-
</div>
196-
</Collapsible.Trigger>
197-
</div>
198-
<Collapsible.Content class="space-y-2">
199-
<div class="px-4">
200-
{#await getFieldStats(field.name)}
201-
<p>loading...</p>
202-
{:then stats}
203-
{#each stats.items as { value, count }}
204-
<div class="flex items-center space-x-4 text-sm text-gray-400">
205-
<code class="flex grow">{value}</code>
206-
<code>{count}</code>
207-
</div>
208-
<Progress value={count} max={stats.max} class="h-2 w-full" />
209-
{/each}
210-
{:catch error}
211-
<p>Error: {error.message}</p>
212-
{/await}
186+
<Collapsible.Root class="my-1 text-sm">
187+
<Collapsible.Trigger class="w-full">
188+
<div class="flex items-center px-4 py-1 text-slate-500 hover:bg-gray-100">
189+
<code class="flex grow">
190+
{field.name}
191+
</code>
192+
<Datatype type={field.data_type} />
213193
</div>
194+
</Collapsible.Trigger>
195+
<Collapsible.Content class="px-4">
196+
{#await getFieldStats(field.name)}
197+
<p>loading...</p>
198+
{:then stats}
199+
{#each stats.items as { value, count }}
200+
<div class="flex items-center text-xs text-gray-400">
201+
<code class="flex grow text-nowrap">{value}</code>
202+
<code class="w-min-[10px]">{count}</code>
203+
</div>
204+
<Progress value={count} max={stats.max} class="my-1 h-1 w-full" />
205+
{/each}
206+
{:catch error}
207+
<p>Error: {error.message}</p>
208+
{/await}
214209
</Collapsible.Content>
215210
</Collapsible.Root>
216211
{/each}
217212
</Resizable.Pane>
218213
<Resizable.Handle />
219-
<Resizable.Pane>
214+
<Resizable.Pane defaultSize={80} minSize={48}>
220215
<ScrollArea class="h-[75vh]">
221216
{#each logs as log}
222217
<LogItem {...log} />

0 commit comments

Comments
 (0)