Skip to content

Commit 6d42a9b

Browse files
author
Matteo Biggio
committed
fix(console): fix column sorting in resources tab (#488)
In the Resources tab, columns names were being associates to the wrong sorting keys, and some column names were just missing from the `SortBy` implementation. All columns have been associated to the corresponding sorting keys, and for the `Location` column, a structured type has been stored in the resource object, in order to sort lexicographically on the path and with conventional numeric ordering on row and column. Also, sorting for attributes as been implemented by sorting lexicographically on the first attribute of each resource row, even if that is probably sub-optimal
1 parent 8269b5f commit 6d42a9b

File tree

3 files changed

+103
-35
lines changed

3 files changed

+103
-35
lines changed

tokio-console/src/state/mod.rs

+46-11
Original file line numberDiff line numberDiff line change
@@ -522,19 +522,54 @@ fn truncate_registry_path(s: String) -> String {
522522
};
523523
}
524524

525-
fn format_location(loc: Option<proto::Location>) -> String {
526-
loc.map(|mut l| {
527-
if let Some(file) = l.file.take() {
528-
let truncated = truncate_registry_path(file);
529-
l.file = Some(truncated);
530-
}
531-
l.to_string()
532-
})
533-
.unwrap_or_else(|| "<unknown location>".to_string())
534-
}
535-
536525
fn pb_duration(dur: prost_types::Duration) -> Duration {
537526
let secs = u64::try_from(dur.seconds).expect("duration should not be negative!");
538527
let nanos = u64::try_from(dur.nanos).expect("duration should not be negative!");
539528
Duration::from_secs(secs) + Duration::from_nanos(nanos)
540529
}
530+
531+
#[derive(Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd)]
532+
pub(crate) struct Location {
533+
path: Option<String>,
534+
line: Option<u32>,
535+
column: Option<u32>,
536+
}
537+
538+
impl fmt::Display for Location {
539+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
540+
match self.path.as_ref() {
541+
Some(path) => f.write_str(path)?,
542+
// If there's no path, then printing the line and
543+
// column makes no sense...
544+
None => return f.write_str("<unknown location>"),
545+
};
546+
547+
if let Some(line) = self.line {
548+
write!(f, ":{}", line)?;
549+
550+
// Printing the column only makes sense if there's a line...
551+
if let Some(column) = self.column {
552+
write!(f, ":{}", column)?;
553+
}
554+
}
555+
556+
Ok(())
557+
}
558+
}
559+
560+
impl From<proto::Location> for Location {
561+
fn from(value: proto::Location) -> Self {
562+
let path = match (value.module_path, value.file) {
563+
// Module paths take precedence because they're shorter...
564+
(Some(module), _) => Some(module),
565+
(None, Some(file)) => Some(truncate_registry_path(file)),
566+
(None, None) => None,
567+
};
568+
569+
Self {
570+
path,
571+
column: value.column,
572+
line: value.line,
573+
}
574+
}
575+
}

tokio-console/src/state/resources.rs

+51-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::intern::{self, InternedStr};
22
use crate::state::{
3-
format_location,
43
store::{self, Id, SpanId, Store},
54
Attribute, Field, Metadata, Visibility,
65
};
@@ -14,6 +13,8 @@ use std::{
1413
time::{Duration, SystemTime},
1514
};
1615

16+
use super::Location;
17+
1718
#[derive(Default, Debug)]
1819
pub(crate) struct ResourcesState {
1920
resources: Store<Resource>,
@@ -29,11 +30,15 @@ pub(crate) enum TypeVisibility {
2930
#[derive(Debug, Copy, Clone)]
3031
#[repr(usize)]
3132
pub(crate) enum SortBy {
32-
Rid = 0,
33-
Kind = 1,
34-
ConcreteType = 2,
35-
Target = 3,
36-
Total = 4,
33+
Id = 0,
34+
ParentId = 1,
35+
Kind = 2,
36+
Total = 3,
37+
Target = 4,
38+
ConcreteType = 5,
39+
Visibility = 6,
40+
Location = 7,
41+
Attributes = 8,
3742
}
3843

3944
#[derive(Debug)]
@@ -55,7 +60,7 @@ pub(crate) struct Resource {
5560
stats: ResourceStats,
5661
target: InternedStr,
5762
concrete_type: InternedStr,
58-
location: String,
63+
location: Location,
5964
visibility: TypeVisibility,
6065
}
6166

@@ -71,27 +76,50 @@ struct ResourceStats {
7176

7277
impl Default for SortBy {
7378
fn default() -> Self {
74-
Self::Rid
79+
Self::Id
7580
}
7681
}
7782

7883
impl SortBy {
7984
pub fn sort(&self, now: SystemTime, resources: &mut [ResourceRef]) {
8085
match self {
81-
Self::Rid => {
86+
Self::Id => {
8287
resources.sort_unstable_by_key(|resource| resource.upgrade().map(|r| r.borrow().id))
8388
}
89+
Self::ParentId => resources.sort_unstable_by_key(|resource| {
90+
resource.upgrade().map(|r| r.borrow().parent_id.clone())
91+
}),
8492
Self::Kind => resources.sort_unstable_by_key(|resource| {
8593
resource.upgrade().map(|r| r.borrow().kind.clone())
8694
}),
95+
Self::Total => resources
96+
.sort_unstable_by_key(|resource| resource.upgrade().map(|r| r.borrow().total(now))),
97+
Self::Target => resources.sort_unstable_by_key(|resource| {
98+
resource.upgrade().map(|r| r.borrow().target.clone())
99+
}),
87100
Self::ConcreteType => resources.sort_unstable_by_key(|resource| {
88101
resource.upgrade().map(|r| r.borrow().concrete_type.clone())
89102
}),
90-
Self::Target => resources.sort_unstable_by_key(|resource| {
91-
resource.upgrade().map(|r| r.borrow().target.clone())
103+
Self::Visibility => resources
104+
.sort_unstable_by_key(|resource| resource.upgrade().map(|r| r.borrow().visibility)),
105+
Self::Location => resources.sort_unstable_by_key(|resource| {
106+
resource.upgrade().map(|r| r.borrow().location.clone())
107+
}),
108+
Self::Attributes => resources.sort_unstable_by_key(|resource| {
109+
resource.upgrade().map(|r| {
110+
// FIXME - we are taking only the first span as sorting key here,
111+
// and we are sorting each attribute as a String.
112+
// Instead, attributes should probably be parsed and sorted according to their actual values,
113+
// not just as strings.
114+
r.borrow()
115+
.formatted_attributes()
116+
.iter()
117+
.flatten()
118+
.next()
119+
.cloned()
120+
.map(|s| s.content)
121+
})
92122
}),
93-
Self::Total => resources
94-
.sort_unstable_by_key(|resource| resource.upgrade().map(|r| r.borrow().total(now))),
95123
}
96124
}
97125
}
@@ -100,11 +128,15 @@ impl TryFrom<usize> for SortBy {
100128
type Error = ();
101129
fn try_from(idx: usize) -> Result<Self, Self::Error> {
102130
match idx {
103-
idx if idx == Self::Rid as usize => Ok(Self::Rid),
131+
idx if idx == Self::Id as usize => Ok(Self::Id),
132+
idx if idx == Self::ParentId as usize => Ok(Self::ParentId),
104133
idx if idx == Self::Kind as usize => Ok(Self::Kind),
105-
idx if idx == Self::ConcreteType as usize => Ok(Self::ConcreteType),
106-
idx if idx == Self::Target as usize => Ok(Self::Target),
107134
idx if idx == Self::Total as usize => Ok(Self::Total),
135+
idx if idx == Self::Target as usize => Ok(Self::Target),
136+
idx if idx == Self::ConcreteType as usize => Ok(Self::ConcreteType),
137+
idx if idx == Self::Visibility as usize => Ok(Self::Visibility),
138+
idx if idx == Self::Location as usize => Ok(Self::Location),
139+
idx if idx == Self::Attributes as usize => Ok(Self::Attributes),
108140
_ => Err(()),
109141
}
110142
}
@@ -202,7 +234,7 @@ impl ResourcesState {
202234
.unwrap_or_else(|| "n/a".to_string()),
203235
);
204236

205-
let location = format_location(resource.location);
237+
let location = resource.location.map(|l| l.into()).unwrap_or_default();
206238
let visibility = if resource.is_internal {
207239
TypeVisibility::Internal
208240
} else {
@@ -309,8 +341,8 @@ impl Resource {
309341
self.stats.total.is_some()
310342
}
311343

312-
pub(crate) fn location(&self) -> &str {
313-
&self.location
344+
pub(crate) fn location(&self) -> String {
345+
self.location.to_string()
314346
}
315347
}
316348

tokio-console/src/state/tasks.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::{
22
intern::{self, InternedStr},
33
state::{
4-
format_location,
54
histogram::DurationHistogram,
65
pb_duration,
76
store::{self, Id, SpanId, Store},
@@ -21,6 +20,8 @@ use std::{
2120
time::{Duration, SystemTime},
2221
};
2322

23+
use super::Location;
24+
2425
#[derive(Default, Debug)]
2526
pub(crate) struct TasksState {
2627
tasks: Store<Task>,
@@ -101,7 +102,7 @@ pub(crate) struct Task {
101102
/// Currently active warnings for this task.
102103
warnings: Vec<Linter<Task>>,
103104
/// The source file and line number the task was spawned from
104-
location: String,
105+
location: Location,
105106
/// The kind of task, currently one of task, blocking, block_on, local
106107
kind: InternedStr,
107108
}
@@ -217,7 +218,7 @@ impl TasksState {
217218
let span_id = task.id?.id;
218219

219220
let stats = stats_update.remove(&span_id)?.into();
220-
let location = format_location(task.location);
221+
let location = task.location.map(|l| l.into()).unwrap_or_default();
221222

222223
// remap the server's ID to a pretty, sequential task ID
223224
let id = ids.id_for(span_id);
@@ -496,8 +497,8 @@ impl Task {
496497
}
497498
}
498499

499-
pub(crate) fn location(&self) -> &str {
500-
&self.location
500+
pub(crate) fn location(&self) -> String {
501+
self.location.to_string()
501502
}
502503
}
503504

0 commit comments

Comments
 (0)