accesslog

package
v0.1.7 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2026 License: GPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package accesslog buffers, batches and reports access-log entries to the panel, per node. It is ported from the local XrayR fork service/accesslog (engine-neutral part) and re-railed for Sing2: there is no xray-core app/log stream to wrap, so the log-handler capture layer (xrayLogHandler / buildEntry / regex parsing) is dropped and replaced by a non-blocking Ingest entry point. The caller (billing hook) constructs each api.AccessLogEntry from connection metadata and hands it in directly. See doc/11 §13.

Index

Constants

View Source
const (
	ProbeBroadcast = "broadcast" // send untagged probe rows to every node
	ProbeFirst     = "first"     // send only to the first registered node
	ProbeNone      = "none"      // drop untagged probe rows
)

Probe report policies (untagged rows with no user, e.g. auth failure / scan).

Variables

This section is empty.

Functions

func FormatRow added in v0.0.6

func FormatRow(t time.Time, r Row) string

FormatRow renders one line, newline included. Exported for the tests, which are the only thing standing between this format and silent drift.

Types

type Config

type Config struct {
	Enable            bool   `mapstructure:"Enable"`
	ReportInvalidUser *bool  `mapstructure:"ReportInvalidUser"` // nil => true (report probe rows)
	ProbeReportPolicy string `mapstructure:"ProbeReportPolicy"` // broadcast | first | none
	BatchSize         int    `mapstructure:"BatchSize"`
	FlushInterval     string `mapstructure:"FlushInterval"` // duration string, e.g. "3s"
	MaxBatch          int    `mapstructure:"MaxBatch"`
	BufferMax         int    `mapstructure:"BufferMax"` // per-node buffer cap
	IngestChanSize    int    `mapstructure:"IngestChanSize"`
}

Config is the process-level access-log reporting configuration. It lives at the top level (sibling of Log) because a single Sing2 process runs a shared access stream for all nodes. Per-node auth (NodeID) is taken from each node's existing ApiConfig via Register. Ported verbatim from the local XrayR fork service/accesslog/config.go (engine-neutral part). See doc/11 §13.1.

type FileLogger added in v0.0.6

type FileLogger struct {
	// contains filtered or unexported fields
}

FileLogger appends rows to a file. Log never blocks: it is called from the per-connection hot path, so a stalled disk must cost log lines, not forwarding. Same rule the panel reporter follows (doc/11 §13).

func NewFileLogger added in v0.0.6

func NewFileLogger(path string, loc *time.Location) (*FileLogger, error)

NewFileLogger opens path for appending and starts the writer goroutine. loc is the timezone for timestamps; nil means the system's local time.

func (*FileLogger) Close added in v0.0.6

func (l *FileLogger) Close()

Close stops the writer, waits for it to drain and flush, and returns. Idempotent.

The wait is bounded: a wedged disk must not be able to hang shutdown. Losing the tail of the log in that case is the right trade — it is already the scenario where writes were failing anyway.

func (*FileLogger) Log added in v0.0.6

func (l *FileLogger) Log(r Row)

Log queues a row, dropping it if the writer is behind. Never blocks.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager consumes access-log entries from the ingest channel, routes them to per-node buffers by inbound tag, and flushes each buffer to its panel in batches. It is a process-level singleton owned by the panel orchestrator.

func New

func New(cfg *Config) *Manager

New creates a Manager. Unlike the XrayR original it takes no core.Instance or logger: capture is via the explicit Ingest entry point, not a wrapped app/log handler (doc/11 §13.2).

func (*Manager) Close

func (m *Manager) Close()

Close stops the manager. In-flight buffers get a best-effort final drain in each flush goroutine.

closeOnce, not a select/default: the latter is a check-then-act and two concurrent Closes both take the default branch and both close, which panics. Reachable because a config reload and SIGTERM can tear down the same Panel at once (doc/14 C-06).

func (*Manager) Ingest

func (m *Manager) Ingest(entry api.AccessLogEntry, tag string)

Ingest is the non-blocking capture entry point (replaces XrayR's inline xrayLogHandler.Handle). It is called on the proxy hot path: the entry is posted to the ingest channel and, if the channel is full, dropped rather than blocking forwarding (doc/11 §13.2, cf. manager.go:289-293). tag is the NodeTag segment of the join key; empty means an untagged probe row routed per ProbeReportPolicy. Untagged rows are skipped entirely when ReportInvalidUser is disabled.

func (*Manager) Register

func (m *Manager) Register(tag string, reporter api.AccessLogReporter, nodeID int)

Register adds a node's reporting target keyed by its inbound tag. Controllers call it during Start (before Manager.Start) and again on node rebuild when the tag changes — a late registration after Start launches the new target's flusher immediately so its rows are flushed instead of counted as dropped.

func (*Manager) Start

func (m *Manager) Start()

Start launches the consumer/flusher/stats goroutines. Register all nodes before calling Start.

func (*Manager) Unregister added in v0.0.11

func (m *Manager) Unregister(tag string)

Unregister drops a node's target and stops its flusher, after one last drain.

Needed because a node's tag is derived from its port (panel.buildNodeTag), so any node rebuild that changes the port produces a NEW tag and Register is called again. Without this the old target stayed in m.routes and m.all forever with its flusher goroutine still ticking — one leaked goroutine per rebuild, and a node that rebuilds on a loop (the failure mode node_stability_test.go exists for) leaks one per cycle. The stale entry also blocked re-registering the same tag later, because Register returns early when the tag already exists.

Unknown tags are a no-op, so callers can invoke it unconditionally.

type Row added in v0.0.6

type Row struct {
	Action   string // "accepted" / "rejected"
	SrcIP    string
	SrcPort  uint16
	Network  string // "tcp" / "udp"
	DestHost string
	DestPort uint16
	InTag    string
	OutTag   string
	User     string // the billing join key "NodeTag|email|uid"
	Reason   string // rejected rows only
}

Row is one access-log line's worth of data, already flattened by the caller.

Jump to

Keyboard shortcuts

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