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 ¶
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 ¶
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 ¶
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
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.