ipn: add c2n endpoint for sockstats logs

Signed-off-by: Will Norris <will@tailscale.com>
pull/7554/head
Will Norris 2 years ago committed by Will Norris
parent a1d9f65354
commit 09e0ccf4c2

@ -83,6 +83,9 @@ func (b *LocalBackend) handleC2N(w http.ResponseWriter, r *http.Request) {
return return
} }
writeJSON(res) writeJSON(res)
case "/sockstats":
w.Header().Set("Content-Type", "text/plain")
b.sockstatLogger.WriteLogs(w)
default: default:
http.Error(w, "unknown c2n path", http.StatusBadRequest) http.Error(w, "unknown c2n path", http.StatusBadRequest)
} }

@ -310,7 +310,7 @@ func NewLocalBackend(logf logger.Logf, logid string, store ipn.StateStore, diale
// for now, only log sockstats on unstable builds // for now, only log sockstats on unstable builds
if version.IsUnstableBuild() { if version.IsUnstableBuild() {
b.sockstatLogger, err = sockstatlog.NewLogger(logpolicy.LogsDir(logf)) b.sockstatLogger, err = sockstatlog.NewLogger(logpolicy.LogsDir(logf), logf)
if err != nil { if err != nil {
log.Printf("error setting up sockstat logger: %v", err) log.Printf("error setting up sockstat logger: %v", err)
} }

@ -6,12 +6,14 @@ package sockstatlog
import ( import (
"encoding/json" "encoding/json"
"io"
"os" "os"
"path/filepath" "path/filepath"
"time" "time"
"tailscale.com/logtail/filch" "tailscale.com/logtail/filch"
"tailscale.com/net/sockstats" "tailscale.com/net/sockstats"
"tailscale.com/types/logger"
"tailscale.com/util/mak" "tailscale.com/util/mak"
) )
@ -21,6 +23,7 @@ const pollPeriod = time.Second / 10
// Logger logs statistics about network sockets. // Logger logs statistics about network sockets.
type Logger struct { type Logger struct {
ticker time.Ticker ticker time.Ticker
logf logger.Logf
logbuffer *filch.Filch logbuffer *filch.Filch
} }
@ -46,7 +49,7 @@ type event struct {
// NewLogger returns a new Logger that will store stats in logdir. // NewLogger returns a new Logger that will store stats in logdir.
// On platforms that do not support sockstat logging, a nil Logger will be returned. // On platforms that do not support sockstat logging, a nil Logger will be returned.
// The returned Logger is not yet running. // The returned Logger is not yet running.
func NewLogger(logdir string) (*Logger, error) { func NewLogger(logdir string, logf logger.Logf) (*Logger, error) {
if !sockstats.IsAvailable { if !sockstats.IsAvailable {
return nil, nil return nil, nil
} }
@ -62,6 +65,7 @@ func NewLogger(logdir string) (*Logger, error) {
return &Logger{ return &Logger{
ticker: *time.NewTicker(pollPeriod), ticker: *time.NewTicker(pollPeriod),
logf: logf,
logbuffer: filch, logbuffer: filch,
}, nil }, nil
} }
@ -92,7 +96,9 @@ func (l *Logger) poll() {
if stats.CurrentInterfaceCellular { if stats.CurrentInterfaceCellular {
e.IsCellularInterface = 1 e.IsCellularInterface = 1
} }
enc.Encode(e) if err := enc.Encode(e); err != nil {
l.logf("sockstatlog: error encoding log: %v", err)
}
} }
} }
lastTime = t lastTime = t
@ -105,6 +111,27 @@ func (l *Logger) Shutdown() {
l.logbuffer.Close() l.logbuffer.Close()
} }
// WriteLogs reads local logs, combining logs into events, and writes them to w.
// Logs within eventWindow are combined into the same event.
func (l *Logger) WriteLogs(w io.Writer) {
if l == nil || l.logbuffer == nil {
return
}
for {
b, err := l.logbuffer.TryReadLine()
if err != nil {
l.logf("sockstatlog: error reading log: %v", err)
return
}
if b == nil {
// no more log messages
return
}
w.Write(b)
}
}
// delta calculates the delta stats between two SockStats snapshots. // delta calculates the delta stats between two SockStats snapshots.
// b is assumed to have occurred after a. // b is assumed to have occurred after a.
// Zero values are omitted from the returned map, and an empty map is returned if no bytes were transferred. // Zero values are omitted from the returned map, and an empty map is returned if no bytes were transferred.

Loading…
Cancel
Save