mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-25 09:03:10 +01:00
chore: apply gofmt formatting
This commit is contained in:
@@ -127,17 +127,17 @@ type SaveDumpOptions struct {
|
|||||||
|
|
||||||
// GameplayOptions has various gameplay modifiers
|
// GameplayOptions has various gameplay modifiers
|
||||||
type GameplayOptions struct {
|
type GameplayOptions struct {
|
||||||
FeaturedWeapons int // Number of Active Feature weapons to generate daily
|
FeaturedWeapons int // Number of Active Feature weapons to generate daily
|
||||||
MaximumNP int // Maximum number of NP held by a player
|
MaximumNP int // Maximum number of NP held by a player
|
||||||
MaximumRP uint16 // Maximum number of RP held by a player
|
MaximumRP uint16 // Maximum number of RP held by a player
|
||||||
MaximumFP uint32 // Maximum number of Festa Points held by a player
|
MaximumFP uint32 // Maximum number of Festa Points held by a player
|
||||||
DisableLoginBoost bool // Disables the Login Boost system
|
DisableLoginBoost bool // Disables the Login Boost system
|
||||||
DisableBoostTime bool // Disables the daily NetCafe Boost Time
|
DisableBoostTime bool // Disables the daily NetCafe Boost Time
|
||||||
BoostTimeDuration int // The number of minutes NetCafe Boost Time lasts for
|
BoostTimeDuration int // The number of minutes NetCafe Boost Time lasts for
|
||||||
ClanMealDuration int // Seconds that a Clan Meal can be activated for after cooking
|
ClanMealDuration int // Seconds that a Clan Meal can be activated for after cooking
|
||||||
ClanMemberLimits [][]uint8 // Array of maximum Clan Members -> [[Rank, Members], ...]
|
ClanMemberLimits [][]uint8 // Array of maximum Clan Members -> [[Rank, Members], ...]
|
||||||
BonusQuestAllowance uint32 // Number of Bonus Point Quests to allow daily
|
BonusQuestAllowance uint32 // Number of Bonus Point Quests to allow daily
|
||||||
DailyQuestAllowance uint32 // Number of Daily Quests to allow daily
|
DailyQuestAllowance uint32 // Number of Daily Quests to allow daily
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logging holds the logging configuration.
|
// Logging holds the logging configuration.
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
// Packet Structure:
|
// Packet Structure:
|
||||||
//
|
//
|
||||||
// MHF packets follow this wire format:
|
// MHF packets follow this wire format:
|
||||||
// [2 bytes: Opcode][N bytes: Packet-specific data][2 bytes: Footer 0x00 0x10]
|
//
|
||||||
|
// [2 bytes: Opcode][N bytes: Packet-specific data][2 bytes: Footer 0x00 0x10]
|
||||||
//
|
//
|
||||||
// Each packet type defines its own structure matching the binary format expected
|
// Each packet type defines its own structure matching the binary format expected
|
||||||
// by the Monster Hunter Frontier client.
|
// by the Monster Hunter Frontier client.
|
||||||
|
|||||||
@@ -514,9 +514,9 @@ func TestMsgMhfUpdateEtcPointOpcode(t *testing.T) {
|
|||||||
// TestAchievementPacketParse tests simple achievement packet parsing
|
// TestAchievementPacketParse tests simple achievement packet parsing
|
||||||
func TestAchievementPacketParse(t *testing.T) {
|
func TestAchievementPacketParse(t *testing.T) {
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint8(5) // AchievementID
|
bf.WriteUint8(5) // AchievementID
|
||||||
bf.WriteUint16(100) // Unk1
|
bf.WriteUint16(100) // Unk1
|
||||||
bf.WriteUint16(200) // Unk2
|
bf.WriteUint16(200) // Unk2
|
||||||
bf.Seek(0, io.SeekStart)
|
bf.Seek(0, io.SeekStart)
|
||||||
|
|
||||||
pkt := &MsgMhfAddAchievement{}
|
pkt := &MsgMhfAddAchievement{}
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ func TestMsgMhfGetAchievementDetailedParse(t *testing.T) {
|
|||||||
// TestMsgMhfAddAchievementDetailedParse tests MsgMhfAddAchievement parsing
|
// TestMsgMhfAddAchievementDetailedParse tests MsgMhfAddAchievement parsing
|
||||||
func TestMsgMhfAddAchievementDetailedParse(t *testing.T) {
|
func TestMsgMhfAddAchievementDetailedParse(t *testing.T) {
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint8(42) // AchievementID
|
bf.WriteUint8(42) // AchievementID
|
||||||
bf.WriteUint16(12345) // Unk1
|
bf.WriteUint16(12345) // Unk1
|
||||||
bf.WriteUint16(0xFFFF) // Unk2 - max value
|
bf.WriteUint16(0xFFFF) // Unk2 - max value
|
||||||
bf.Seek(0, io.SeekStart)
|
bf.Seek(0, io.SeekStart)
|
||||||
|
|
||||||
pkt := &MsgMhfAddAchievement{}
|
pkt := &MsgMhfAddAchievement{}
|
||||||
@@ -61,12 +61,12 @@ func TestMsgMhfAddAchievementDetailedParse(t *testing.T) {
|
|||||||
// TestMsgSysCastBinaryDetailedParse tests MsgSysCastBinary parsing with various payloads
|
// TestMsgSysCastBinaryDetailedParse tests MsgSysCastBinary parsing with various payloads
|
||||||
func TestMsgSysCastBinaryDetailedParse(t *testing.T) {
|
func TestMsgSysCastBinaryDetailedParse(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
unk0 uint16
|
unk0 uint16
|
||||||
unk1 uint16
|
unk1 uint16
|
||||||
broadcastType uint8
|
broadcastType uint8
|
||||||
messageType uint8
|
messageType uint8
|
||||||
payload []byte
|
payload []byte
|
||||||
}{
|
}{
|
||||||
{"empty payload", 0, 0, 1, 2, []byte{}},
|
{"empty payload", 0, 0, 1, 2, []byte{}},
|
||||||
{"typical payload", 100, 200, 0x10, 0x20, []byte{0x01, 0x02, 0x03}},
|
{"typical payload", 100, 200, 0x10, 0x20, []byte{0x01, 0x02, 0x03}},
|
||||||
|
|||||||
@@ -139,8 +139,8 @@ func TestGetAchData_ValueAccumulation(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetAchData_NextValueByLevel(t *testing.T) {
|
func TestGetAchData_NextValueByLevel(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
level uint8
|
level uint8
|
||||||
wantNext uint16
|
wantNext uint16
|
||||||
approxScore int32
|
approxScore int32
|
||||||
}{
|
}{
|
||||||
{0, 5, 0},
|
{0, 5, 0},
|
||||||
|
|||||||
@@ -311,4 +311,3 @@ func TestEmptyHandlers_NoDb(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,13 +44,13 @@ import (
|
|||||||
|
|
||||||
// Config holds configuration parameters for creating a new channel server.
|
// Config holds configuration parameters for creating a new channel server.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ID uint16 // Channel server ID (unique identifier)
|
ID uint16 // Channel server ID (unique identifier)
|
||||||
Logger *zap.Logger // Logger instance for this channel server
|
Logger *zap.Logger // Logger instance for this channel server
|
||||||
DB *sqlx.DB // Database connection pool
|
DB *sqlx.DB // Database connection pool
|
||||||
DiscordBot *discordbot.DiscordBot // Optional Discord bot for chat integration
|
DiscordBot *discordbot.DiscordBot // Optional Discord bot for chat integration
|
||||||
ErupeConfig *config.Config // Global Erupe configuration
|
ErupeConfig *config.Config // Global Erupe configuration
|
||||||
Name string // Display name for the server (shown in broadcasts)
|
Name string // Display name for the server (shown in broadcasts)
|
||||||
Enable bool // Whether this server is enabled
|
Enable bool // Whether this server is enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// userBinaryPartID is a composite key for identifying a specific part of a user's binary data.
|
// userBinaryPartID is a composite key for identifying a specific part of a user's binary data.
|
||||||
@@ -86,15 +86,15 @@ type Server struct {
|
|||||||
erupeConfig *config.Config // Global configuration
|
erupeConfig *config.Config // Global configuration
|
||||||
|
|
||||||
// Connection management
|
// Connection management
|
||||||
acceptConns chan net.Conn // Channel for new accepted connections
|
acceptConns chan net.Conn // Channel for new accepted connections
|
||||||
deleteConns chan net.Conn // Channel for connections to be cleaned up
|
deleteConns chan net.Conn // Channel for connections to be cleaned up
|
||||||
sessions map[net.Conn]*Session // Active sessions keyed by connection
|
sessions map[net.Conn]*Session // Active sessions keyed by connection
|
||||||
listener net.Listener // TCP listener (created when Server.Start is called)
|
listener net.Listener // TCP listener (created when Server.Start is called)
|
||||||
isShuttingDown bool // Shutdown flag to stop goroutines gracefully
|
isShuttingDown bool // Shutdown flag to stop goroutines gracefully
|
||||||
|
|
||||||
// Stage (game room) management
|
// Stage (game room) management
|
||||||
stagesLock sync.RWMutex // Protects stages map (RWMutex for concurrent reads)
|
stagesLock sync.RWMutex // Protects stages map (RWMutex for concurrent reads)
|
||||||
stages map[string]*Stage // Active stages keyed by stage ID string
|
stages map[string]*Stage // Active stages keyed by stage ID string
|
||||||
|
|
||||||
// Localization
|
// Localization
|
||||||
dict map[string]string // Language string mappings for server messages
|
dict map[string]string // Language string mappings for server messages
|
||||||
@@ -105,9 +105,9 @@ type Server struct {
|
|||||||
userBinaryParts map[userBinaryPartID][]byte // Chunked binary data by character
|
userBinaryParts map[userBinaryPartID][]byte // Chunked binary data by character
|
||||||
|
|
||||||
// Semaphore (multiplayer coordination) management
|
// Semaphore (multiplayer coordination) management
|
||||||
semaphoreLock sync.RWMutex // Protects semaphore map and semaphoreIndex
|
semaphoreLock sync.RWMutex // Protects semaphore map and semaphoreIndex
|
||||||
semaphore map[string]*Semaphore // Active semaphores keyed by semaphore ID
|
semaphore map[string]*Semaphore // Active semaphores keyed by semaphore ID
|
||||||
semaphoreIndex uint32 // Auto-incrementing ID for new semaphores (starts at 7)
|
semaphoreIndex uint32 // Auto-incrementing ID for new semaphores (starts at 7)
|
||||||
|
|
||||||
// Optional integrations
|
// Optional integrations
|
||||||
discordBot *discordbot.DiscordBot // Discord bot for chat relay (nil if disabled)
|
discordBot *discordbot.DiscordBot // Discord bot for chat relay (nil if disabled)
|
||||||
|
|||||||
@@ -48,32 +48,32 @@ type Session struct {
|
|||||||
sync.Mutex // Protects session state during concurrent handler execution
|
sync.Mutex // Protects session state during concurrent handler execution
|
||||||
|
|
||||||
// Core connection and logging
|
// Core connection and logging
|
||||||
logger *zap.Logger // Logger with connection address
|
logger *zap.Logger // Logger with connection address
|
||||||
server *Server // Parent server reference
|
server *Server // Parent server reference
|
||||||
rawConn net.Conn // Underlying TCP connection
|
rawConn net.Conn // Underlying TCP connection
|
||||||
cryptConn *network.CryptConn // Encrypted connection wrapper
|
cryptConn *network.CryptConn // Encrypted connection wrapper
|
||||||
sendPackets chan packet // Outbound packet queue (buffered, size 20)
|
sendPackets chan packet // Outbound packet queue (buffered, size 20)
|
||||||
clientContext *clientctx.ClientContext // Client version and capabilities
|
clientContext *clientctx.ClientContext // Client version and capabilities
|
||||||
lastPacket time.Time // Timestamp of last received packet (for timeout detection)
|
lastPacket time.Time // Timestamp of last received packet (for timeout detection)
|
||||||
|
|
||||||
// Stage (game area) state
|
// Stage (game area) state
|
||||||
userEnteredStage bool // Whether player has entered any stage during this session
|
userEnteredStage bool // Whether player has entered any stage during this session
|
||||||
stageID string // Current stage ID string (e.g., "sl1Ns200p0a0u0")
|
stageID string // Current stage ID string (e.g., "sl1Ns200p0a0u0")
|
||||||
stage *Stage // Pointer to current stage object
|
stage *Stage // Pointer to current stage object
|
||||||
reservationStage *Stage // Stage reserved for quest (used by unreserve packet)
|
reservationStage *Stage // Stage reserved for quest (used by unreserve packet)
|
||||||
stagePass string // Temporary password storage for password-protected stages
|
stagePass string // Temporary password storage for password-protected stages
|
||||||
stageMoveStack *stringstack.StringStack // Navigation history for "back" functionality
|
stageMoveStack *stringstack.StringStack // Navigation history for "back" functionality
|
||||||
|
|
||||||
// Player identity and state
|
// Player identity and state
|
||||||
charID uint32 // Character ID for this session
|
charID uint32 // Character ID for this session
|
||||||
Name string // Character name (for debugging/logging)
|
Name string // Character name (for debugging/logging)
|
||||||
prevGuildID uint32 // Last guild ID queried (cached for InfoGuild)
|
prevGuildID uint32 // Last guild ID queried (cached for InfoGuild)
|
||||||
token string // Authentication token from sign server
|
token string // Authentication token from sign server
|
||||||
logKey []byte // Logging encryption key
|
logKey []byte // Logging encryption key
|
||||||
sessionStart int64 // Session start timestamp (Unix time)
|
sessionStart int64 // Session start timestamp (Unix time)
|
||||||
courses []mhfcourse.Course // Active Monster Hunter courses (buffs/subscriptions)
|
courses []mhfcourse.Course // Active Monster Hunter courses (buffs/subscriptions)
|
||||||
kqf []byte // Key Quest Flags (quest progress tracking)
|
kqf []byte // Key Quest Flags (quest progress tracking)
|
||||||
kqfOverride bool // Whether KQF is being overridden
|
kqfOverride bool // Whether KQF is being overridden
|
||||||
|
|
||||||
// Quest/event coordination
|
// Quest/event coordination
|
||||||
semaphore *Semaphore // Semaphore for quest/event participation (if in a coordinated activity)
|
semaphore *Semaphore // Semaphore for quest/event participation (if in a coordinated activity)
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
// other players in the same stage. Each object has an owner, position, and
|
// other players in the same stage. Each object has an owner, position, and
|
||||||
// unique ID for client-server synchronization.
|
// unique ID for client-server synchronization.
|
||||||
type Object struct {
|
type Object struct {
|
||||||
sync.RWMutex // Protects object state during updates
|
sync.RWMutex // Protects object state during updates
|
||||||
id uint32 // Unique object ID (see NextObjectID for ID generation)
|
id uint32 // Unique object ID (see NextObjectID for ID generation)
|
||||||
ownerCharID uint32 // Character ID of the player who placed this object
|
ownerCharID uint32 // Character ID of the player who placed this object
|
||||||
x, y, z float32 // 3D position coordinates
|
x, y, z float32 // 3D position coordinates
|
||||||
}
|
}
|
||||||
|
|
||||||
// stageBinaryKey is a composite key for identifying a specific piece of stage binary data.
|
// stageBinaryKey is a composite key for identifying a specific piece of stage binary data.
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ import (
|
|||||||
// A session is identified by the combination of channel and IP:port, tracking
|
// A session is identified by the combination of channel and IP:port, tracking
|
||||||
// all activities from when a player connects until they disconnect.
|
// all activities from when a player connects until they disconnect.
|
||||||
type PlayerSession struct {
|
type PlayerSession struct {
|
||||||
Name string // Player name
|
Name string // Player name
|
||||||
IPPort string // Client IP address and port (e.g., "192.168.1.1:12345")
|
IPPort string // Client IP address and port (e.g., "192.168.1.1:12345")
|
||||||
Channel string // Server channel (e.g., "channel-4")
|
Channel string // Server channel (e.g., "channel-4")
|
||||||
FirstSeen time.Time // Timestamp of first activity
|
FirstSeen time.Time // Timestamp of first activity
|
||||||
LastSeen time.Time // Timestamp of last activity
|
LastSeen time.Time // Timestamp of last activity
|
||||||
Activities []string // List of player activities
|
Activities []string // List of player activities
|
||||||
Stages []string // List of stage changes
|
Stages []string // List of stage changes
|
||||||
Objects []string // List of objects broadcast by this player
|
Objects []string // List of objects broadcast by this player
|
||||||
Errors int // Number of errors encountered during session
|
Errors int // Number of errors encountered during session
|
||||||
SaveCount int // Number of save operations performed
|
SaveCount int // Number of save operations performed
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectionStats aggregates statistics about player connections across all sessions.
|
// ConnectionStats aggregates statistics about player connections across all sessions.
|
||||||
@@ -31,12 +31,12 @@ type PlayerSession struct {
|
|||||||
// This structure tracks high-level metrics useful for understanding server usage
|
// This structure tracks high-level metrics useful for understanding server usage
|
||||||
// patterns, peak times, and common connection issues.
|
// patterns, peak times, and common connection issues.
|
||||||
type ConnectionStats struct {
|
type ConnectionStats struct {
|
||||||
TotalConnections int // Total number of player sessions
|
TotalConnections int // Total number of player sessions
|
||||||
UniqueIPs map[string]int // IP addresses to connection count
|
UniqueIPs map[string]int // IP addresses to connection count
|
||||||
UniquePlayers map[string]bool // Set of unique player names
|
UniquePlayers map[string]bool // Set of unique player names
|
||||||
ConnectionsPerDay map[string]int // Date to connection count
|
ConnectionsPerDay map[string]int // Date to connection count
|
||||||
ChannelDistribution map[string]int // Channel to connection count
|
ChannelDistribution map[string]int // Channel to connection count
|
||||||
DisconnectReasons map[string]int // Disconnect reason to count
|
DisconnectReasons map[string]int // Disconnect reason to count
|
||||||
}
|
}
|
||||||
|
|
||||||
// runConnections implements the connections command for analyzing player connection patterns.
|
// runConnections implements the connections command for analyzing player connection patterns.
|
||||||
@@ -61,9 +61,10 @@ type ConnectionStats struct {
|
|||||||
// - v: Verbose output including objects and stage changes
|
// - v: Verbose output including objects and stage changes
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// runConnections([]string{"-stats"})
|
//
|
||||||
// runConnections([]string{"-sessions", "-v"})
|
// runConnections([]string{"-stats"})
|
||||||
// runConnections([]string{"-player", "Sarah", "-sessions"})
|
// runConnections([]string{"-sessions", "-v"})
|
||||||
|
// runConnections([]string{"-player", "Sarah", "-sessions"})
|
||||||
func runConnections(args []string) {
|
func runConnections(args []string) {
|
||||||
fs := flag.NewFlagSet("connections", flag.ExitOnError)
|
fs := flag.NewFlagSet("connections", flag.ExitOnError)
|
||||||
|
|
||||||
@@ -160,7 +161,7 @@ func runConnections(args []string) {
|
|||||||
|
|
||||||
// Track disconnections
|
// Track disconnections
|
||||||
if strings.Contains(entry.Message, "Error on ReadPacket, exiting recv loop") ||
|
if strings.Contains(entry.Message, "Error on ReadPacket, exiting recv loop") ||
|
||||||
strings.Contains(entry.Message, "Error reading packet") {
|
strings.Contains(entry.Message, "Error reading packet") {
|
||||||
sessionKey := extractSessionKey(entry.Logger)
|
sessionKey := extractSessionKey(entry.Logger)
|
||||||
if session, exists := sessions[sessionKey]; exists {
|
if session, exists := sessions[sessionKey]; exists {
|
||||||
session.Errors++
|
session.Errors++
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import (
|
|||||||
// Errors can be grouped by message, caller, or logger to identify patterns
|
// Errors can be grouped by message, caller, or logger to identify patterns
|
||||||
// and recurring issues in the logs.
|
// and recurring issues in the logs.
|
||||||
type ErrorGroup struct {
|
type ErrorGroup struct {
|
||||||
Message string // Primary message for this error group
|
Message string // Primary message for this error group
|
||||||
Count int // Total number of occurrences
|
Count int // Total number of occurrences
|
||||||
FirstSeen string // Timestamp of first occurrence
|
FirstSeen string // Timestamp of first occurrence
|
||||||
LastSeen string // Timestamp of last occurrence
|
LastSeen string // Timestamp of last occurrence
|
||||||
Examples []*LogEntry // Sample log entries (limited by the limit flag)
|
Examples []*LogEntry // Sample log entries (limited by the limit flag)
|
||||||
Callers map[string]int // Map of caller locations to occurrence counts
|
Callers map[string]int // Map of caller locations to occurrence counts
|
||||||
}
|
}
|
||||||
|
|
||||||
// runErrors implements the errors command for extracting and analyzing errors.
|
// runErrors implements the errors command for extracting and analyzing errors.
|
||||||
@@ -44,9 +44,10 @@ type ErrorGroup struct {
|
|||||||
// - detailed: Show detailed information including examples and extra data
|
// - detailed: Show detailed information including examples and extra data
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// runErrors([]string{"-summary"})
|
//
|
||||||
// runErrors([]string{"-detailed", "-stack"})
|
// runErrors([]string{"-summary"})
|
||||||
// runErrors([]string{"-group", "caller", "-limit", "20"})
|
// runErrors([]string{"-detailed", "-stack"})
|
||||||
|
// runErrors([]string{"-group", "caller", "-limit", "20"})
|
||||||
func runErrors(args []string) {
|
func runErrors(args []string) {
|
||||||
fs := flag.NewFlagSet("errors", flag.ExitOnError)
|
fs := flag.NewFlagSet("errors", flag.ExitOnError)
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,10 @@ import (
|
|||||||
// All filters are combined with AND logic.
|
// All filters are combined with AND logic.
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// runFilter([]string{"-level", "error"})
|
//
|
||||||
// runFilter([]string{"-since", "1h", "-logger", "channel-4*"})
|
// runFilter([]string{"-level", "error"})
|
||||||
// runFilter([]string{"-msg", "connection reset", "-count"})
|
// runFilter([]string{"-since", "1h", "-logger", "channel-4*"})
|
||||||
|
// runFilter([]string{"-msg", "connection reset", "-count"})
|
||||||
func runFilter(args []string) {
|
func runFilter(args []string) {
|
||||||
fs := flag.NewFlagSet("filter", flag.ExitOnError)
|
fs := flag.NewFlagSet("filter", flag.ExitOnError)
|
||||||
|
|
||||||
@@ -137,9 +138,10 @@ func runFilter(args []string) {
|
|||||||
// - true if the string matches the pattern, false otherwise
|
// - true if the string matches the pattern, false otherwise
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// matchWildcard("channel-4", "channel-*") // returns true
|
//
|
||||||
// matchWildcard("main.channel-4.error", "*channel-4*") // returns true
|
// matchWildcard("channel-4", "channel-*") // returns true
|
||||||
// matchWildcard("test", "foo*") // returns false
|
// matchWildcard("main.channel-4.error", "*channel-4*") // returns true
|
||||||
|
// matchWildcard("test", "foo*") // returns false
|
||||||
func matchWildcard(s, pattern string) bool {
|
func matchWildcard(s, pattern string) bool {
|
||||||
if pattern == "*" {
|
if pattern == "*" {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -16,10 +16,11 @@ import (
|
|||||||
// - tail: Follow logs in real-time (like tail -f)
|
// - tail: Follow logs in real-time (like tail -f)
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// loganalyzer <command> [options]
|
//
|
||||||
// loganalyzer filter -level error -since 1h
|
// loganalyzer <command> [options]
|
||||||
// loganalyzer errors -summary
|
// loganalyzer filter -level error -since 1h
|
||||||
// loganalyzer stats -detailed
|
// loganalyzer errors -summary
|
||||||
|
// loganalyzer stats -detailed
|
||||||
func main() {
|
func main() {
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
fmt.Fprintf(os.Stderr, "Erupe Log Analyzer - Suite of tools to analyze erupe.log files\n\n")
|
fmt.Fprintf(os.Stderr, "Erupe Log Analyzer - Suite of tools to analyze erupe.log files\n\n")
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import (
|
|||||||
// LogEntry represents a parsed log entry from either JSON or timestamp-based format.
|
// LogEntry represents a parsed log entry from either JSON or timestamp-based format.
|
||||||
//
|
//
|
||||||
// The parser supports two log formats:
|
// The parser supports two log formats:
|
||||||
// 1. JSON format: {"level":"info","ts":1762989571.547817,"logger":"main","msg":"Starting"}
|
// 1. JSON format: {"level":"info","ts":1762989571.547817,"logger":"main","msg":"Starting"}
|
||||||
// 2. Timestamp format: 2025-11-12T23:19:31.546Z INFO commands Command Help: Enabled
|
// 2. Timestamp format: 2025-11-12T23:19:31.546Z INFO commands Command Help: Enabled
|
||||||
type LogEntry struct {
|
type LogEntry struct {
|
||||||
Raw string // Original log line
|
Raw string // Original log line
|
||||||
Level string // Log level: info, warn, error, fatal
|
Level string // Log level: info, warn, error, fatal
|
||||||
@@ -50,11 +50,12 @@ type LogEntry struct {
|
|||||||
// - An error if the file cannot be opened or read
|
// - An error if the file cannot be opened or read
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// entries, err := ParseLogFile("erupe.log")
|
//
|
||||||
// if err != nil {
|
// entries, err := ParseLogFile("erupe.log")
|
||||||
// log.Fatal(err)
|
// if err != nil {
|
||||||
// }
|
// log.Fatal(err)
|
||||||
// fmt.Printf("Parsed %d entries\n", len(entries))
|
// }
|
||||||
|
// fmt.Printf("Parsed %d entries\n", len(entries))
|
||||||
func ParseLogFile(filename string) ([]*LogEntry, error) {
|
func ParseLogFile(filename string) ([]*LogEntry, error) {
|
||||||
file, err := os.Open(filename)
|
file, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -92,9 +93,9 @@ func ParseLogFile(filename string) ([]*LogEntry, error) {
|
|||||||
// ParseLogLine parses a single log line into a LogEntry.
|
// ParseLogLine parses a single log line into a LogEntry.
|
||||||
//
|
//
|
||||||
// This function attempts to parse the line in the following order:
|
// This function attempts to parse the line in the following order:
|
||||||
// 1. JSON format: Lines starting with '{' are parsed as JSON objects
|
// 1. JSON format: Lines starting with '{' are parsed as JSON objects
|
||||||
// 2. Timestamp format: Tab-delimited lines with RFC3339 timestamps
|
// 2. Timestamp format: Tab-delimited lines with RFC3339 timestamps
|
||||||
// 3. Unknown format: Lines that don't match either format are marked as "unknown" level
|
// 3. Unknown format: Lines that don't match either format are marked as "unknown" level
|
||||||
//
|
//
|
||||||
// For JSON logs, all standard fields (level, ts, logger, caller, msg, error, stacktrace)
|
// For JSON logs, all standard fields (level, ts, logger, caller, msg, error, stacktrace)
|
||||||
// are extracted, and any additional fields are stored in ExtraData.
|
// are extracted, and any additional fields are stored in ExtraData.
|
||||||
@@ -106,8 +107,9 @@ func ParseLogFile(filename string) ([]*LogEntry, error) {
|
|||||||
// - A LogEntry pointer containing the parsed data, or nil if the line is invalid
|
// - A LogEntry pointer containing the parsed data, or nil if the line is invalid
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// entry := ParseLogLine(`{"level":"info","ts":1762989571.547817,"msg":"Starting"}`)
|
//
|
||||||
// fmt.Println(entry.Level, entry.Message)
|
// entry := ParseLogLine(`{"level":"info","ts":1762989571.547817,"msg":"Starting"}`)
|
||||||
|
// fmt.Println(entry.Level, entry.Message)
|
||||||
func ParseLogLine(line string) *LogEntry {
|
func ParseLogLine(line string) *LogEntry {
|
||||||
entry := &LogEntry{
|
entry := &LogEntry{
|
||||||
Raw: line,
|
Raw: line,
|
||||||
@@ -152,7 +154,7 @@ func ParseLogLine(line string) *LogEntry {
|
|||||||
// Store any extra fields
|
// Store any extra fields
|
||||||
for k, v := range jsonData {
|
for k, v := range jsonData {
|
||||||
if k != "level" && k != "ts" && k != "logger" && k != "caller" &&
|
if k != "level" && k != "ts" && k != "logger" && k != "caller" &&
|
||||||
k != "msg" && k != "error" && k != "stacktrace" {
|
k != "msg" && k != "error" && k != "stacktrace" {
|
||||||
entry.ExtraData[k] = v
|
entry.ExtraData[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,12 +203,13 @@ func ParseLogLine(line string) *LogEntry {
|
|||||||
// - An error if the file cannot be opened, read, or if the callback returns an error
|
// - An error if the file cannot be opened, read, or if the callback returns an error
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// err := StreamLogFile("erupe.log", func(entry *LogEntry) error {
|
//
|
||||||
// if entry.Level == "error" {
|
// err := StreamLogFile("erupe.log", func(entry *LogEntry) error {
|
||||||
// fmt.Println(entry.Message)
|
// if entry.Level == "error" {
|
||||||
// }
|
// fmt.Println(entry.Message)
|
||||||
// return nil
|
// }
|
||||||
// })
|
// return nil
|
||||||
|
// })
|
||||||
func StreamLogFile(filename string, callback func(*LogEntry) error) error {
|
func StreamLogFile(filename string, callback func(*LogEntry) error) error {
|
||||||
file, err := os.Open(filename)
|
file, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -259,9 +262,10 @@ func StreamLogFile(filename string, callback func(*LogEntry) error) error {
|
|||||||
// - A formatted string representation of the log entry
|
// - A formatted string representation of the log entry
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// formatted := FormatLogEntry(entry, true)
|
//
|
||||||
// fmt.Println(formatted)
|
// formatted := FormatLogEntry(entry, true)
|
||||||
// // Output: 2025-11-12 23:19:31.546 INFO [main] Starting Erupe
|
// fmt.Println(formatted)
|
||||||
|
// // Output: 2025-11-12 23:19:31.546 INFO [main] Starting Erupe
|
||||||
func FormatLogEntry(entry *LogEntry, colorize bool) string {
|
func FormatLogEntry(entry *LogEntry, colorize bool) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
|
|
||||||
|
|||||||
@@ -15,19 +15,19 @@ import (
|
|||||||
// message types, and server operations to provide insights into server behavior
|
// message types, and server operations to provide insights into server behavior
|
||||||
// and activity patterns.
|
// and activity patterns.
|
||||||
type LogStats struct {
|
type LogStats struct {
|
||||||
TotalEntries int // Total number of log entries
|
TotalEntries int // Total number of log entries
|
||||||
EntriesByLevel map[string]int // Log level to count
|
EntriesByLevel map[string]int // Log level to count
|
||||||
EntriesByLogger map[string]int // Logger name to count
|
EntriesByLogger map[string]int // Logger name to count
|
||||||
EntriesByDay map[string]int // Date string to count
|
EntriesByDay map[string]int // Date string to count
|
||||||
EntriesByHour map[int]int // Hour (0-23) to count
|
EntriesByHour map[int]int // Hour (0-23) to count
|
||||||
TopMessages map[string]int // Message text to count
|
TopMessages map[string]int // Message text to count
|
||||||
FirstEntry time.Time // Timestamp of first entry
|
FirstEntry time.Time // Timestamp of first entry
|
||||||
LastEntry time.Time // Timestamp of last entry
|
LastEntry time.Time // Timestamp of last entry
|
||||||
SaveOperations int // Count of save operations
|
SaveOperations int // Count of save operations
|
||||||
ObjectBroadcasts int // Count of object broadcasts
|
ObjectBroadcasts int // Count of object broadcasts
|
||||||
StageChanges int // Count of stage changes
|
StageChanges int // Count of stage changes
|
||||||
TerminalLogs int // Count of terminal log entries
|
TerminalLogs int // Count of terminal log entries
|
||||||
UniqueCallers map[string]bool // Set of unique caller locations
|
UniqueCallers map[string]bool // Set of unique caller locations
|
||||||
}
|
}
|
||||||
|
|
||||||
// runStats implements the stats command for generating comprehensive log statistics.
|
// runStats implements the stats command for generating comprehensive log statistics.
|
||||||
@@ -49,9 +49,10 @@ type LogStats struct {
|
|||||||
// - detailed: Show detailed statistics including temporal patterns and top messages
|
// - detailed: Show detailed statistics including temporal patterns and top messages
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// runStats([]string{}) // Basic statistics
|
//
|
||||||
// runStats([]string{"-detailed"}) // Full statistics with temporal analysis
|
// runStats([]string{}) // Basic statistics
|
||||||
// runStats([]string{"-detailed", "-top", "20"}) // Show top 20 items
|
// runStats([]string{"-detailed"}) // Full statistics with temporal analysis
|
||||||
|
// runStats([]string{"-detailed", "-top", "20"}) // Show top 20 items
|
||||||
func runStats(args []string) {
|
func runStats(args []string) {
|
||||||
fs := flag.NewFlagSet("stats", flag.ExitOnError)
|
fs := flag.NewFlagSet("stats", flag.ExitOnError)
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import (
|
|||||||
// useful for real-time monitoring of server activity.
|
// useful for real-time monitoring of server activity.
|
||||||
//
|
//
|
||||||
// The command operates in two phases:
|
// The command operates in two phases:
|
||||||
// 1. Initial display: Shows the last N matching entries from the file
|
// 1. Initial display: Shows the last N matching entries from the file
|
||||||
// 2. Follow mode: Continuously monitors for new lines and displays them as they appear
|
// 2. Follow mode: Continuously monitors for new lines and displays them as they appear
|
||||||
//
|
//
|
||||||
// Both phases support filtering by log level and colorized output.
|
// Both phases support filtering by log level and colorized output.
|
||||||
//
|
//
|
||||||
@@ -30,10 +30,11 @@ import (
|
|||||||
// The follow mode polls the file every 100ms for new content. Use Ctrl+C to stop.
|
// The follow mode polls the file every 100ms for new content. Use Ctrl+C to stop.
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// runTail([]string{}) // Show last 10 lines and follow
|
//
|
||||||
// runTail([]string{"-n", "50"}) // Show last 50 lines and follow
|
// runTail([]string{}) // Show last 10 lines and follow
|
||||||
// runTail([]string{"-level", "error"}) // Only show errors
|
// runTail([]string{"-n", "50"}) // Show last 50 lines and follow
|
||||||
// runTail([]string{"-follow=false", "-n", "20"}) // Just show last 20 lines, don't follow
|
// runTail([]string{"-level", "error"}) // Only show errors
|
||||||
|
// runTail([]string{"-follow=false", "-n", "20"}) // Just show last 20 lines, don't follow
|
||||||
func runTail(args []string) {
|
func runTail(args []string) {
|
||||||
fs := flag.NewFlagSet("tail", flag.ExitOnError)
|
fs := flag.NewFlagSet("tail", flag.ExitOnError)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user