godevtool

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 28, 2026 License: MIT Imports: 29 Imported by: 0

README

godevtool

A comprehensive developer debugging toolkit for Go applications.

Zero external dependencies. 26 packages. 180 tests. Real-time web dashboard.

Features

Category Features
Logging Structured, colorized logger with levels, key-value pairs, child loggers
Inspection Pretty-print any Go value with type info, nested structs, slices, maps
Timing Execution timer with defer pattern, aggregate stats (min/max/avg)
Stack Traces Capture and format stack traces with runtime frame filtering
HTTP Middleware Capture incoming request/response details, headers, bodies, timing
Goroutines Monitor count, detect leaks, view goroutine state
Memory Track heap, GC cycles, allocation rates
Database Log SQL queries with timing, args, caller info; wraps *sql.DB
Timeline Record events and spans across your application lifecycle
Config Viewer Display configuration with automatic secret redaction
Error Tracking Group errors, track rates (1m/5m/15m), panic recovery middleware
Profiler On-demand CPU/heap/goroutine/mutex profiles with download
HTTP Tracing Trace outgoing HTTP with DNS/TCP/TLS/server timing breakdown
Cache Monitor Track hit/miss/eviction rates across named caches
Rate Limits Monitor rate limiter decisions (allowed/throttled/queued)
Benchmarks Micro-benchmark runner with P50/P90/P99 percentiles
Alerts Threshold-based alert rules with firing/resolved state machine
Export Export debug snapshots as JSON or self-contained HTML reports
gRPC Monitor gRPC calls (unary/stream, server/client)
Hot Reload File watcher with auto-rebuild on .go file changes
Dashboard Real-time web UI with 19 tabs, SSE streaming, dark theme

Installation

go get github.com/nahaktarun/godevtool

Requires Go 1.21 or later.

Quick Start

package main

import (
    "github.com/nahaktarun/godevtool"
    "github.com/nahaktarun/godevtool/log"
)

func main() {
    dt := godevtool.New(
        godevtool.WithAppName("myapp"),
        godevtool.WithLogLevel(log.LevelDebug),
    )
    defer dt.Shutdown()

    // Structured logging
    dt.Log.Info("server starting", "port", 8080, "env", "development")

    // Inspect any value
    dt.Inspect(myStruct)

    // Time operations
    defer dt.Timer("database-query").Stop()

    // Start the web dashboard
    dt.StartDashboard(":9999")
    // Open http://localhost:9999 in your browser
}

Usage Guide

Logging
dt := godevtool.New(godevtool.WithAppName("api"))

dt.Log.Info("request received", "method", "GET", "path", "/users")
dt.Log.Warn("cache miss", "key", "user:42")
dt.Log.Error("query failed", err, "table", "users")
dt.Log.Debug("parsed payload", "size", 1024)

// Child logger with persistent context
reqLog := dt.Log.With("request_id", "abc-123", "user_id", 42)
reqLog.Info("processing")

Output:

15:04:05.123 INFO  [api] request received              method=GET path=/users
15:04:05.124 WARN  [api] cache miss                    key=user:42
15:04:05.125 ERROR [api] query failed                  error="connection refused" table=users
Variable Inspector
type User struct {
    Name    string
    Email   string
    Roles   []string
    Address struct {
        City  string
        State string
    }
}

dt.Inspect(User{
    Name:  "Alice",
    Email: "alice@example.com",
    Roles: []string{"admin", "editor"},
    Address: struct{ City, State string }{"Springfield", "IL"},
})

Output:

(main.User) {
  Name   : (string) "Alice"
  Email  : (string) "alice@example.com"
  Roles  : ([]string) [2 items] [
    [0] (string) "admin"
    [1] (string) "editor"
  ]
  Address: (struct) {
    City : (string) "Springfield"
    State: (string) "IL"
  }
}
HTTP Middleware
mux := http.NewServeMux()
mux.HandleFunc("/api/users", handleUsers)

// Wrap with devtool middleware - captures all requests
handler := dt.Middleware().Handler(mux)

// Add panic recovery
handler = dt.RecoverMiddleware(handler)

http.ListenAndServe(":8080", handler)
Execution Timer
// Simple timing with defer
func processOrder(id string) {
    defer dt.Timer("process-order").Stop()
    // ... work ...
}

// View aggregate stats
dt.PrintTimerReport()
// Output:
// LABEL            COUNT   TOTAL         AVG          MIN          MAX
// process-order        5   250ms         50ms         30ms         80ms
Web Dashboard
// Start monitors
dt.StartGoroutineMonitor(3 * time.Second)
dt.StartMemStats(3 * time.Second)

// Launch dashboard on a separate port
dt.StartDashboard(":9999")
// Open http://localhost:9999

The dashboard provides 19 real-time tabs: Overview, Logs, Requests, Goroutines, Memory, Timers, Queries, Timeline, Config, Errors, Environment, Dependencies, Profiler, Outgoing HTTP, Caches, Rate Limits, Benchmarks, Alerts, gRPC.

Database Query Logging
import "github.com/nahaktarun/godevtool/dblog"

// Wrap your *sql.DB
wrappedDB := dblog.WrapDB(db, dt.DBLogger())

// All queries are now automatically logged
rows, err := wrappedDB.QueryContext(ctx, "SELECT * FROM users WHERE id = $1", 42)
Event Timeline
import "github.com/nahaktarun/godevtool/timeline"

// Point-in-time events
dt.TimelineRecord(timeline.CatHTTP, "GET /api/users", map[string]any{"status": 200})

// Spans (events with duration)
span := dt.TimelineStart(timeline.CatDB, "SELECT * FROM users", nil)
// ... do work ...
span.SetData("rows", 15)
span.End()
Configuration Viewer
type Config struct {
    Host     string `json:"host" env:"APP_HOST"`
    Port     int    `json:"port"`
    DBPass   string `devtool:"redact"` // automatically masked
    APIKey   string `devtool:"redact"` // automatically masked
}

dt.RegisterConfig("app", Config{
    Host:   "localhost",
    Port:   8080,
    DBPass: "secret123",
    APIKey: "sk-prod-xxxxx",
})

dt.PrintConfig()
// Output:
// app
//   Host     localhost  (string)  [env:APP_HOST]
//   Port     8080       (int)    [json:port]
//   DBPass   ********   (string)
//   APIKey   ********   (string)
Error Tracking
// Track errors
dt.TrackError(err, map[string]any{"endpoint": "/api/users"})

// Panic recovery middleware
handler = dt.RecoverMiddleware(handler)

// View stats
dt.PrintErrorStats()
// Groups similar errors, shows rates for last 1m/5m/15m
Profiling
// Capture heap snapshot
prof, _ := dt.CaptureHeapProfile()

// Capture CPU profile (blocking for duration)
prof, _ := dt.CaptureCPUProfile(30 * time.Second)

// Profiles are downloadable from the dashboard
HTTP Client Tracing
// Wrap any http.Client
client := dt.WrapHTTPClient(&http.Client{Timeout: 10 * time.Second})

// All requests are traced with timing breakdown
resp, err := client.Get("https://api.example.com/data")
// Captures: DNS lookup, TCP connect, TLS handshake, server processing, content transfer
Cache Monitoring
cache := dt.RegisterCache("users")

// In your cache implementation:
if value, ok := myCache.Get(key); ok {
    cache.Hit()
} else {
    cache.Miss()
}
cache.SetSize(int64(myCache.Len()))
Benchmarking
result := dt.Benchmark("json-marshal", 10000, func() {
    json.Marshal(data)
})
// result.AvgTime, result.P50, result.P90, result.P99, result.OpsPerSec
Alert Rules
// Built-in rules
dt.AlertOnGoroutineCount(100)            // warn if > 100 goroutines
dt.AlertOnHeapAlloc(512 * 1024 * 1024)   // warn if heap > 512MB

// Custom rules
dt.AddAlertRule(alerts.CustomRule(
    "error_rate", alerts.SeverityCritical, 10,
    "error rate exceeds threshold",
    func() (float64, bool) {
        stats := dt.ErrorTracker().Stats()
        return float64(stats.Last5Min), stats.Last5Min > 10
    },
))

// Start evaluation
dt.StartAlerts(10 * time.Second)
Export Debug Sessions
// Export as JSON
data, _ := dt.ExportJSON()

// Export as self-contained HTML report
data, _ := dt.ExportHTML()

// Write to file
dt.ExportToFile("debug-report.html", "html")

// Also available from the dashboard via Export buttons
Hot Reload
import "github.com/nahaktarun/godevtool/hotreload"

dt.StartHotReload(
    hotreload.WithDirs("."),
    hotreload.WithBuildCmd("go build -o ./tmp/main ."),
    hotreload.WithDebounce(500 * time.Millisecond),
)
Production Safety
dt := godevtool.New()

// Disable in production - all methods become no-ops
if os.Getenv("ENV") == "production" {
    dt.Disable()
}

Configuration Options

dt := godevtool.New(
    godevtool.WithAppName("myapp"),           // prefix for log lines
    godevtool.WithLogLevel(log.LevelDebug),   // min log level
    godevtool.WithOutput(os.Stderr),          // output destination
    godevtool.WithNoColor(),                  // disable ANSI colors
    godevtool.WithTimeFormat("2006-01-02 15:04:05"), // timestamp format
    godevtool.WithMaxDepth(15),               // inspect recursion depth
)

Package Architecture

godevtool/
├── godevtool.go           Main DevTool facade (57 public methods)
├── options.go             Configuration options
├── internal/
│   ├── color/             ANSI color helpers
│   └── ringbuf/           Generic thread-safe ring buffer
├── log/                   Structured pretty logger
├── inspect/               Variable/struct inspector
├── timer/                 Execution timer + reports
├── stack/                 Stack trace prettifier
├── middleware/             HTTP request/response capture
├── goroutine/             Goroutine monitor + leak detection
├── memstats/              Memory/GC stats collector
├── dashboard/             Web dashboard + SSE + REST API
│   └── static/            Embedded HTML/JS/CSS
├── dblog/                 Database query logger
├── timeline/              Event timeline with spans
├── config/                Config viewer with redaction
├── environ/               Environment detector
├── deps/                  Dependency scanner
├── errtrack/              Error tracker + panic recovery
├── profiler/              Pprof integration
├── httptrace/             HTTP client tracer
├── cachemon/              Cache monitor
├── ratelimit/             Rate limiter monitor
├── bench/                 Benchmark runner
├── alerts/                Alert rules engine
├── export/                JSON/HTML export
├── grpcmon/               gRPC call monitor
├── hotreload/             File watcher + auto-rebuild
└── examples/
    ├── basic/             CLI-only demo
    ├── http-server/       HTTP server with debug endpoints
    └── full-dashboard/    Full demo with all features

Examples

Basic (CLI only)
go run examples/basic/main.go
HTTP Server with Debug Endpoints
go run examples/http-server/main.go
# http://localhost:8080/api/users
# http://localhost:8080/debug/requests
Full Dashboard
go run examples/full-dashboard/main.go
# App:       http://localhost:8080
# Dashboard: http://localhost:9999

Design Principles

  • Zero dependencies - Pure Go standard library only
  • Zero overhead when disabled - Disable() makes all methods no-ops
  • No global state - Everything hangs off the DevTool instance
  • Bounded memory - Ring buffers prevent unbounded growth
  • Thread-safe - All types are safe for concurrent use
  • Functional options - Idiomatic Go configuration pattern

API Reference

Full API documentation: pkg.go.dev/github.com/nahaktarun/godevtool

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Run tests (go test ./...)
  4. Commit your changes
  5. Push to the branch
  6. Open a Pull Request

License

MIT License - see LICENSE file for details.

Documentation

Overview

Package godevtool is a comprehensive developer debugging toolkit for Go applications.

It provides structured logging, variable inspection, performance profiling, HTTP request/response monitoring, goroutine tracking, memory analysis, database query logging, event timelines, configuration viewing, error tracking, and a real-time web dashboard -- all with zero external dependencies.

Quick Start

dt := godevtool.New(
    godevtool.WithAppName("myapp"),
    godevtool.WithLogLevel(godevtool.LevelDebug),
)
defer dt.Shutdown()

// Structured logging
dt.Log.Info("server starting", "port", 8080)

// Variable inspection
dt.Inspect(myStruct)

// Execution timing
defer dt.Timer("db-query").Stop()

// Web dashboard
dt.StartDashboard(":9999")

Architecture

The DevTool struct is the central facade that wires together 26 specialized packages. Each package can be used independently, but the facade provides a unified API and connects everything to the web dashboard for real-time visualization.

All features are designed to be zero-overhead when disabled via DevTool.Disable.

Packages

Core debugging:

  • log - Structured, colorized logging with key-value pairs
  • inspect - Pretty-print any Go value with type information
  • timer - Execution timing with aggregate statistics
  • stack - Stack trace capture and formatting

Runtime monitoring:

  • middleware - HTTP request/response capture
  • goroutine - Goroutine count tracking and leak detection
  • memstats - Memory and GC statistics collection

Advanced tracing:

  • dblog - Database query logging with sql.DB wrapping
  • timeline - Event timeline with point-in-time events and spans
  • config - Configuration viewer with field redaction

Environment awareness:

  • environ - Go version, OS, build info, hostname detection
  • deps - Module dependency scanning
  • errtrack - Error tracking, grouping, and panic recovery
  • profiler - On-demand pprof profile capture

Performance intelligence:

  • httptrace - Outgoing HTTP request tracing with timing breakdown
  • cachemon - Cache hit/miss/eviction monitoring
  • ratelimit - Rate limiter decision tracking
  • bench - Micro-benchmarking with percentile statistics

Developer experience:

  • alerts - Configurable threshold alert rules
  • export - Debug session export as JSON or HTML report
  • grpcmon - gRPC call monitoring
  • hotreload - File watching with auto-rebuild
  • dashboard - Real-time web dashboard with SSE

Index

Constants

View Source
const (
	LevelDebug = log.LevelDebug
	LevelInfo  = log.LevelInfo
	LevelWarn  = log.LevelWarn
	LevelError = log.LevelError
)

Re-export log levels for convenience.

Variables

This section is empty.

Functions

This section is empty.

Types

type DevTool

type DevTool struct {
	Log *log.Logger
	// contains filtered or unexported fields
}

DevTool is the central handle for all debugging facilities. It is safe for concurrent use.

func New

func New(opts ...Option) *DevTool

New creates a DevTool instance. Pass Option values to customize behavior.

func (*DevTool) AddAlertRule

func (d *DevTool) AddAlertRule(rule alerts.Rule)

AddAlertRule registers an alert rule.

func (*DevTool) AlertEngine

func (d *DevTool) AlertEngine() *alerts.Engine

AlertEngine returns the alert rules engine.

func (*DevTool) AlertOnGoroutineCount

func (d *DevTool) AlertOnGoroutineCount(threshold int)

AlertOnGoroutineCount adds a rule that fires when goroutine count exceeds threshold.

func (*DevTool) AlertOnHeapAlloc

func (d *DevTool) AlertOnHeapAlloc(thresholdBytes uint64)

AlertOnHeapAlloc adds a rule that fires when heap allocation exceeds threshold bytes.

func (*DevTool) BenchRunner

func (d *DevTool) BenchRunner() *bench.Runner

BenchRunner returns the benchmark runner.

func (*DevTool) Benchmark

func (d *DevTool) Benchmark(label string, n int, fn func()) bench.Result

Benchmark runs fn n times and returns statistics.

func (*DevTool) CacheMonitor

func (d *DevTool) CacheMonitor() *cachemon.Monitor

CacheMonitor returns the cache monitor.

func (*DevTool) CaptureCPUProfile

func (d *DevTool) CaptureCPUProfile(duration time.Duration) (*profiler.Profile, error)

CaptureCPUProfile captures a CPU profile for the given duration.

func (*DevTool) CaptureHeapProfile

func (d *DevTool) CaptureHeapProfile() (*profiler.Profile, error)

CaptureHeapProfile captures a heap profile snapshot.

func (*DevTool) Config

func (d *DevTool) Config() *config.Viewer

Config returns the configuration viewer.

func (*DevTool) DBLogger

func (d *DevTool) DBLogger() *dblog.Logger

DBLogger returns the database query logger. Use dblog.WrapDB(db, dt.DBLogger()) to wrap a *sql.DB.

func (*DevTool) Dependencies

func (d *DevTool) Dependencies() deps.ScanResult

Dependencies returns the module dependency scan result.

func (*DevTool) Disable

func (d *DevTool) Disable()

Disable turns off all output. All methods become no-ops.

func (*DevTool) Enable

func (d *DevTool) Enable()

Enable re-enables output after Disable().

func (*DevTool) Environ

func (d *DevTool) Environ() environ.Info

Environ returns the detected environment info.

func (*DevTool) ErrorTracker

func (d *DevTool) ErrorTracker() *errtrack.Tracker

ErrorTracker returns the error tracker.

func (*DevTool) ExportHTML

func (d *DevTool) ExportHTML() ([]byte, error)

ExportHTML captures a full debug snapshot as a self-contained HTML report.

func (*DevTool) ExportJSON

func (d *DevTool) ExportJSON() ([]byte, error)

ExportJSON captures a full debug snapshot as JSON.

func (*DevTool) ExportToFile

func (d *DevTool) ExportToFile(path, format string) error

ExportToFile writes a debug snapshot to a file.

func (*DevTool) GRPCMonitor

func (d *DevTool) GRPCMonitor() *grpcmon.Monitor

GRPCMonitor returns the gRPC call monitor.

func (*DevTool) GoroutineLeakCheck

func (d *DevTool) GoroutineLeakCheck() []goroutine.GoroutineInfo

GoroutineLeakCheck returns suspected goroutine leaks.

func (*DevTool) GoroutineSnapshot

func (d *DevTool) GoroutineSnapshot() goroutine.Snapshot

GoroutineSnapshot returns the current goroutine snapshot.

func (*DevTool) HTTPTracer

func (d *DevTool) HTTPTracer() *httptrace.Tracer

HTTPTracer returns the HTTP client tracer.

func (*DevTool) HotReloadState

func (d *DevTool) HotReloadState() hotreload.State

HotReloadState returns the current hot reload state.

func (*DevTool) Inspect

func (d *DevTool) Inspect(v any) string

Inspect pretty-prints any Go value to the configured output. Returns the formatted string.

func (*DevTool) InspectTo

func (d *DevTool) InspectTo(w io.Writer, v any) string

InspectTo writes the inspection output to w.

func (*DevTool) MemSnapshot

func (d *DevTool) MemSnapshot() memstats.Snapshot

MemSnapshot returns the current memory snapshot.

func (*DevTool) Middleware

func (d *DevTool) Middleware() *middleware.Inspector

Middleware returns the HTTP request/response inspector.

func (*DevTool) PrintConfig

func (d *DevTool) PrintConfig()

PrintConfig prints all registered configurations to the configured output.

func (*DevTool) PrintDependencies

func (d *DevTool) PrintDependencies()

PrintDependencies prints dependencies to the configured output.

func (*DevTool) PrintEnviron

func (d *DevTool) PrintEnviron()

PrintEnviron prints environment info to the configured output.

func (*DevTool) PrintErrorStats

func (d *DevTool) PrintErrorStats()

PrintErrorStats prints error statistics to the configured output.

func (*DevTool) PrintGoroutines

func (d *DevTool) PrintGoroutines()

PrintGoroutines prints the current goroutine state to output.

func (*DevTool) PrintMemStats

func (d *DevTool) PrintMemStats()

PrintMemStats prints the current memory statistics to output.

func (*DevTool) PrintStack

func (d *DevTool) PrintStack()

PrintStack prints a prettified stack trace to the configured output.

func (*DevTool) PrintTimeline

func (d *DevTool) PrintTimeline(n int)

PrintTimeline prints recent timeline events to the configured output.

func (*DevTool) PrintTimerReport

func (d *DevTool) PrintTimerReport()

PrintTimerReport writes the timing report table to the configured output.

func (*DevTool) Profiler

func (d *DevTool) Profiler() *profiler.Profiler

Profiler returns the profiler.

func (*DevTool) RateLimitMonitor

func (d *DevTool) RateLimitMonitor() *ratelimit.Monitor

RateLimitMonitor returns the rate limiter monitor.

func (*DevTool) RecoverMiddleware

func (d *DevTool) RecoverMiddleware(next http.Handler) http.Handler

RecoverMiddleware returns an HTTP handler that recovers panics and tracks them.

func (*DevTool) RegisterCache

func (d *DevTool) RegisterCache(name string) *cachemon.Recorder

RegisterCache creates a named cache tracker.

func (*DevTool) RegisterConfig

func (d *DevTool) RegisterConfig(name string, cfg any, sources ...map[string]string)

RegisterConfig adds a named configuration struct for display on the dashboard. Fields tagged `devtool:"redact"` will have their values masked.

func (*DevTool) RegisterRateLimiter

func (d *DevTool) RegisterRateLimiter(name string) *ratelimit.Recorder

RegisterRateLimiter creates a named rate limiter tracker.

func (*DevTool) Shutdown

func (d *DevTool) Shutdown()

Shutdown stops all background monitors and the dashboard gracefully.

func (*DevTool) Stack

func (d *DevTool) Stack(skip int) string

Stack returns a prettified stack trace string starting from the caller.

func (*DevTool) StartAlerts

func (d *DevTool) StartAlerts(interval time.Duration)

StartAlerts begins periodic alert rule evaluation.

func (*DevTool) StartDashboard

func (d *DevTool) StartDashboard(addr string) error

StartDashboard starts the web dashboard on the given address (e.g. ":9999"). It wires all subsystems into the dashboard for real-time visualization.

func (*DevTool) StartGoroutineMonitor

func (d *DevTool) StartGoroutineMonitor(interval time.Duration)

StartGoroutineMonitor begins tracking goroutines at the given interval.

func (*DevTool) StartHotReload

func (d *DevTool) StartHotReload(opts ...hotreload.Option) error

StartHotReload begins file watching and auto-rebuild.

func (*DevTool) StartMemStats

func (d *DevTool) StartMemStats(interval time.Duration)

StartMemStats begins collecting memory/GC statistics at the given interval.

func (*DevTool) StopAlerts

func (d *DevTool) StopAlerts()

StopAlerts stops the alert engine.

func (*DevTool) StopDashboard

func (d *DevTool) StopDashboard() error

StopDashboard stops the web dashboard server.

func (*DevTool) StopGoroutineMonitor

func (d *DevTool) StopGoroutineMonitor()

StopGoroutineMonitor stops goroutine tracking.

func (*DevTool) StopHotReload

func (d *DevTool) StopHotReload()

StopHotReload stops the file watcher.

func (*DevTool) StopMemStats

func (d *DevTool) StopMemStats()

StopMemStats stops memory statistics collection.

func (*DevTool) Timeline

func (d *DevTool) Timeline() *timeline.Timeline

Timeline returns the event timeline.

func (*DevTool) TimelineRecord

func (d *DevTool) TimelineRecord(category, label string, data map[string]any) string

TimelineRecord adds a point-in-time event to the timeline.

func (*DevTool) TimelineStart

func (d *DevTool) TimelineStart(category, label string, data map[string]any) *timeline.Span

TimelineStart begins a span on the timeline. Call span.End() to complete it.

func (*DevTool) Timer

func (d *DevTool) Timer(label string) *timer.Timer

Timer returns a started Timer. Call Stop() (typically via defer) to record elapsed time.

defer d.Timer("db-query").Stop()

func (*DevTool) TimerReport

func (d *DevTool) TimerReport() *timer.Report

TimerReport returns the aggregate timing report.

func (*DevTool) TrackError

func (d *DevTool) TrackError(err error, data ...map[string]any)

TrackError records an error occurrence.

func (*DevTool) WrapHTTPClient

func (d *DevTool) WrapHTTPClient(client *http.Client) *http.Client

WrapHTTPClient returns an instrumented *http.Client that traces outgoing requests.

type Option

type Option func(*options)

Option configures a DevTool instance.

func WithAppName

func WithAppName(name string) Option

WithAppName sets an application name prefix for log lines.

func WithColor

func WithColor() Option

WithColor forces ANSI color codes on.

func WithLogLevel

func WithLogLevel(level log.Level) Option

WithLogLevel sets the minimum log level.

func WithMaxDepth

func WithMaxDepth(depth int) Option

WithMaxDepth sets the maximum recursion depth for Inspect.

func WithNoColor

func WithNoColor() Option

WithNoColor disables ANSI color codes.

func WithOutput

func WithOutput(w io.Writer) Option

WithOutput sets the writer for all devtool output.

func WithTimeFormat

func WithTimeFormat(format string) Option

WithTimeFormat sets the timestamp format (Go reference time layout).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL