cmd/tailscale/cli: show last seen time on status command (#16588)

Add a last seen time on the cli's status command, similar to the web
portal.

Before:
```
100.xxx.xxx.xxx    tailscale-operator   tagged-devices linux   offline
```

After:
```
100.xxx.xxx.xxx    tailscale-operator   tagged-devices linux   offline, last seen 20d ago
```

Fixes #16584

Signed-off-by: Mahyar Mirrashed <mah.mirr@gmail.com>
This commit is contained in:
Mahyar Mirrashed
2025-09-22 12:37:27 -05:00
committed by GitHub
parent f67ad67c6f
commit 5e79e497d3
3 changed files with 24 additions and 5 deletions

View File

@@ -18,6 +18,7 @@ import (
"strings" "strings"
"sync" "sync"
"text/tabwriter" "text/tabwriter"
"time"
"github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
@@ -538,3 +539,19 @@ func jsonDocsWalk(cmd *ffcli.Command) *commandDoc {
} }
return res return res
} }
func lastSeenFmt(t time.Time) string {
if t.IsZero() {
return ""
}
d := max(time.Since(t), time.Minute) // at least 1 minute
switch {
case d < time.Hour:
return fmt.Sprintf(", last seen %dm ago", int(d.Minutes()))
case d < 24*time.Hour:
return fmt.Sprintf(", last seen %dh ago", int(d.Hours()))
default:
return fmt.Sprintf(", last seen %dd ago", int(d.Hours()/24))
}
}

View File

@@ -173,11 +173,13 @@ func hasAnyExitNodeSuggestions(peers []*ipnstate.PeerStatus) bool {
// a peer. If there is no notable state, a - is returned. // a peer. If there is no notable state, a - is returned.
func peerStatus(peer *ipnstate.PeerStatus) string { func peerStatus(peer *ipnstate.PeerStatus) string {
if !peer.Active { if !peer.Active {
lastseen := lastSeenFmt(peer.LastSeen)
if peer.ExitNode { if peer.ExitNode {
return "selected but offline" return "selected but offline" + lastseen
} }
if !peer.Online { if !peer.Online {
return "offline" return "offline" + lastseen
} }
} }

View File

@@ -164,7 +164,7 @@ func runStatus(ctx context.Context, args []string) error {
anyTraffic := ps.TxBytes != 0 || ps.RxBytes != 0 anyTraffic := ps.TxBytes != 0 || ps.RxBytes != 0
var offline string var offline string
if !ps.Online { if !ps.Online {
offline = "; offline" offline = "; offline" + lastSeenFmt(ps.LastSeen)
} }
if !ps.Active { if !ps.Active {
if ps.ExitNode { if ps.ExitNode {
@@ -174,7 +174,7 @@ func runStatus(ctx context.Context, args []string) error {
} else if anyTraffic { } else if anyTraffic {
f("idle" + offline) f("idle" + offline)
} else if !ps.Online { } else if !ps.Online {
f("offline") f("offline" + lastSeenFmt(ps.LastSeen))
} else { } else {
f("-") f("-")
} }
@@ -193,7 +193,7 @@ func runStatus(ctx context.Context, args []string) error {
f("peer-relay %s", ps.PeerRelay) f("peer-relay %s", ps.PeerRelay)
} }
if !ps.Online { if !ps.Online {
f("; offline") f(offline)
} }
} }
if anyTraffic { if anyTraffic {