Refactor mclog #29
279
bedrock/log.go
279
bedrock/log.go
@ -1,279 +0,0 @@
|
|||||||
package bedrock
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"slices"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"sirherobrine23.com.br/go-bds/go-bds/mclog"
|
|
||||||
"sirherobrine23.com.br/go-bds/go-bds/regex"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
PlayerActionDisconnect string = "disconnect" // Player disconnected from server
|
|
||||||
PlayerActionConnect string = "connect" // Player connect in to server
|
|
||||||
PlayerActionSpawn string = "spawn" // Player spawned in server and connected correct to server, only new server (1.16+)
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ = mclog.RegisterNewParse(&BedrockLoger{})
|
|
||||||
|
|
||||||
MojangPlayerActions = map[string]*regex.Regexp{
|
|
||||||
// [2024-04-01 20:50:26:198 INFO] Player connected: Sirherobrine, xuid: 2535413418839840
|
|
||||||
// [2024-04-01 21:46:11:691 INFO] Player connected: nod dd, xuid:
|
|
||||||
// [2024-04-01 20:50:31:386 INFO] Player Spawned: Sirherobrine xuid: 2535413418839840
|
|
||||||
// [2024-04-01 21:46:16:637 INFO] Player Spawned: nod dd xuid: , pfid: c31902da495f4549
|
|
||||||
// [2022-08-30 20:56:55:231 INFO] Player disconnected: Sirherobrine, xuid: 2535413418839840
|
|
||||||
// [2024-04-01 21:46:33:199 INFO] Player disconnected: nod dd, xuid: , pfid: c31902da495f4549
|
|
||||||
// NO LOG FILE! - [2025-01-19 23:35:18 INFO] Player connected: 2535413418839840
|
|
||||||
// NO LOG FILE! - [2025-01-19 23:38:54 INFO] Player disconnected: 2535413418839840
|
|
||||||
//
|
|
||||||
// TimeAction = time.Time{}
|
|
||||||
// Action = disconnected|connected|Spawned
|
|
||||||
// Username = String
|
|
||||||
// Xuid = String
|
|
||||||
`v2`: regex.MustCompile(`(?m)^\[(?P<TimeAction>([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})):[0-9]{1,3} INFO\ Player (?P<Action>disconnected|connected|Spawned): (?P<Username>[0-9A-Za-z_\-\s]+), xuid:\s?(?P<Xuid>[0-9A-Za-z]+)?,?`),
|
|
||||||
}
|
|
||||||
MojangPort = map[string]*regex.Regexp{
|
|
||||||
// NO LOG FILE! - [2024-07-30 00:33:21 INFO] IPv4 supported, port: 19132
|
|
||||||
// NO LOG FILE! - [2024-07-30 00:33:21 INFO] IPv6 supported, port: 19133
|
|
||||||
// NO LOG FILE! - [2024-07-30 00:33:22 INFO] Listening on IPv6 port: 19133
|
|
||||||
// NO LOG FILE! - [2024-07-30 00:33:22 INFO] Listening on IPv4 port: 19132
|
|
||||||
// [2023-03-08 13:01:57 INFO] Listening on IPv4 port: 19132
|
|
||||||
`v3`: regex.MustCompile(`(?m)\[(?P<TimeAction>([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})) INFO\] Listening on IPv(?P<Protocol>4|6) port: (?P<Port>[0-9]{1,5})`),
|
|
||||||
// [2024-07-29 20:48:07:066 INFO] IPv4 supported, port: 19132: Used for gameplay and LAN discovery
|
|
||||||
// [2024-07-29 20:48:07:066 INFO] IPv6 supported, port: 19133: Used for gameplay
|
|
||||||
`v2`: regex.MustCompile(`(?m)^\[(?P<TimeAction>([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})):[0-9]{1,3} INFO\] IPv(?P<Protocol>4|6) supported, port: (?P<Port>[0-9]{1,5})`),
|
|
||||||
// [INFO] IPv4 supported, port: 19132
|
|
||||||
`v1`: regex.MustCompile(`(?m)^\[INFO\] IPv(?P<Protocol>4|6) supported, port: (?P<Port>[0-9]{1,5})`),
|
|
||||||
}
|
|
||||||
MojangStarter = map[string]*regex.Regexp{
|
|
||||||
// [2024-04-10 11:16:29:640 INFO] Server started.
|
|
||||||
`v2`: regex.MustCompile(`(?m)^\[(?P<TimeAction>([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})):[0-9]{1,3} INFO\] Server started\.`),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type BedrockLoger struct{}
|
|
||||||
|
|
||||||
func (BedrockLoger) String() string { return "mojang:bedrock" }
|
|
||||||
func (BedrockLoger) New() (mclog.ServerParse, error) { return &LogerParse{mclog.Insights{}}, nil }
|
|
||||||
|
|
||||||
type LogerParse struct {
|
|
||||||
local mclog.Insights
|
|
||||||
}
|
|
||||||
|
|
||||||
func (loger LogerParse) Insight() *mclog.Insights { return &loger.local }
|
|
||||||
func (loger *LogerParse) Detect(log io.ReadSeeker) error {
|
|
||||||
loger.local = mclog.Insights{
|
|
||||||
ID: "mojang/bedrock",
|
|
||||||
Name: "bedrock",
|
|
||||||
Type: "Server log",
|
|
||||||
Title: "bedrock",
|
|
||||||
Version: "unknown",
|
|
||||||
Analysis: map[mclog.LogLevel][]*mclog.InsightsAnalysis{},
|
|
||||||
}
|
|
||||||
|
|
||||||
logScan := bufio.NewScanner(log)
|
|
||||||
isValid := false
|
|
||||||
for logScan.Scan() {
|
|
||||||
text := logScan.Text()
|
|
||||||
if !strings.Contains(text, "]") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
isValid = true
|
|
||||||
|
|
||||||
Analysis := &mclog.InsightsAnalysis{
|
|
||||||
Entry: mclog.AnalysisEntry{
|
|
||||||
Lines: []mclog.EntryLine{
|
|
||||||
{
|
|
||||||
Content: text,
|
|
||||||
Numbers: strings.Count(text, "") - len(strings.Split(text, " ")),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
prefixSplit := strings.SplitN(text, "]", 2)
|
|
||||||
prefixSplit[0] = prefixSplit[0][strings.Index(prefixSplit[0], "[")+1:]
|
|
||||||
if prefixSplit[1] = strings.TrimSpace(prefixSplit[1]); prefixSplit[1] == "" {
|
|
||||||
continue // skip
|
|
||||||
}
|
|
||||||
Analysis.Entry.Prefix = prefixSplit[0]
|
|
||||||
Analysis.Message = prefixSplit[1]
|
|
||||||
Analysis.Value = prefixSplit[1]
|
|
||||||
|
|
||||||
logLevel, add, err := mclog.LogUnknown, false, error(nil)
|
|
||||||
if strings.HasSuffix(prefixSplit[0], "INFO") {
|
|
||||||
logLevel = mclog.LogInfo
|
|
||||||
prefixSplit[0] = prefixSplit[0][:len(prefixSplit[0])-5]
|
|
||||||
} else if strings.HasSuffix(prefixSplit[0], "ERROR") {
|
|
||||||
logLevel = mclog.LogProblem
|
|
||||||
prefixSplit[0] = prefixSplit[0][:len(prefixSplit[0])-6]
|
|
||||||
Analysis.Label = "Error"
|
|
||||||
add = true
|
|
||||||
} else {
|
|
||||||
return mclog.ErrSkipParse
|
|
||||||
}
|
|
||||||
|
|
||||||
// Date
|
|
||||||
if len(prefixSplit[0]) >= 19 {
|
|
||||||
if Analysis.Entry.EntryTime, err = time.ParseInLocation("2006-01-02 15:04:05", prefixSplit[0][:19], time.Local); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
Analysis.Entry.EntryTime = Analysis.Entry.EntryTime.UTC() // Convert to UTC time
|
|
||||||
}
|
|
||||||
|
|
||||||
explodeString := strings.Fields(prefixSplit[1])
|
|
||||||
switch explodeString[0] {
|
|
||||||
case "Server":
|
|
||||||
if strings.Contains(text, "started") {
|
|
||||||
add = true
|
|
||||||
Analysis.Label = "Server started"
|
|
||||||
Analysis.Value = "started"
|
|
||||||
Analysis.Message = "Server started"
|
|
||||||
}
|
|
||||||
case "Version":
|
|
||||||
if len(explodeString) >= 2 {
|
|
||||||
add = true
|
|
||||||
version := explodeString[len(explodeString)-1]
|
|
||||||
loger.local.Version = version
|
|
||||||
Analysis.Value = version
|
|
||||||
Analysis.Label = "Bedrock version"
|
|
||||||
}
|
|
||||||
case "IPv6", "IPv4", "Listening":
|
|
||||||
if explodeString[len(explodeString)-2] == "port:" {
|
|
||||||
protoLocation := 0
|
|
||||||
if explodeString[0] == "Listening" {
|
|
||||||
protoLocation = len(explodeString) - 3
|
|
||||||
}
|
|
||||||
Analysis.Label = explodeString[protoLocation]
|
|
||||||
Analysis.Value = explodeString[len(explodeString)-1]
|
|
||||||
Analysis.Label = "Port"
|
|
||||||
add = true
|
|
||||||
}
|
|
||||||
case "Player":
|
|
||||||
if !slices.Contains([]string{"connected:", "Spawned:", "disconnected:"}, explodeString[1]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
add = true
|
|
||||||
Analysis.Label = explodeString[1][:len(explodeString[1])-1]
|
|
||||||
Analysis.Message = "player connection"
|
|
||||||
|
|
||||||
player := prefixSplit[1][strings.Index(prefixSplit[1], explodeString[1])+len(explodeString[1]):]
|
|
||||||
|
|
||||||
xuid := ""
|
|
||||||
if strings.Contains(player, "xuid:") {
|
|
||||||
xuid = player[strings.LastIndex(player, "xuid:")+5:]
|
|
||||||
player = player[:strings.LastIndex(player, "xuid:")-2]
|
|
||||||
if strings.Contains(xuid, ",") {
|
|
||||||
xuid = xuid[:strings.Index(player, ",")]
|
|
||||||
}
|
|
||||||
xuid = strings.TrimSpace(xuid)
|
|
||||||
player = strings.TrimSpace(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
Analysis.Value = player
|
|
||||||
Analysis.External = PlayerConnection{
|
|
||||||
Player: player,
|
|
||||||
XUID: xuid,
|
|
||||||
Action: Analysis.Label,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if add {
|
|
||||||
Analysis.Counter = len(Analysis.Entry.Lines)
|
|
||||||
loger.local.Analysis[logLevel] = append(loger.local.Analysis[logLevel], Analysis)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isValid {
|
|
||||||
return mclog.ErrSkipParse
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PlayerConnection struct {
|
|
||||||
Player string `json:"player"` // Player username
|
|
||||||
XUID string `json:"xuid,omitempty"` // Player xuid
|
|
||||||
Action string `json:"action"` // Connection type
|
|
||||||
}
|
|
||||||
|
|
||||||
type Handlers struct {
|
|
||||||
Started *time.Time `json:"started"` // Server started date
|
|
||||||
Ports []uint16 `json:"ports"` // Server ports
|
|
||||||
Players []PlayerConnection `json:"players"` // Player connnections in to server
|
|
||||||
}
|
|
||||||
|
|
||||||
// Server avaible time to player connect
|
|
||||||
func (w *Handlers) ParseStarted(logline string) {
|
|
||||||
for _, reg := range MojangStarter {
|
|
||||||
if reg.MatchString(logline) {
|
|
||||||
var err error
|
|
||||||
matched := reg.FindAllGroups(logline)
|
|
||||||
w.Started = new(time.Time)
|
|
||||||
if timeStr, ok := matched["TimeAction"]; ok {
|
|
||||||
if *w.Started, err = time.ParseInLocation(`2006-01-02 15:04:05`, timeStr, time.Local); err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if timeStr, ok := matched["Time"]; ok {
|
|
||||||
if *w.Started, err = time.ParseInLocation(`2006-01-02 15:04:05`, timeStr, time.Local); err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*w.Started = time.Now()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Player action
|
|
||||||
func (w *Handlers) ParsePlayer(logline string) {
|
|
||||||
for _, reg := range MojangPlayerActions {
|
|
||||||
if reg.MatchString(logline) {
|
|
||||||
ActionPlayer := reg.FindAllGroups(logline)
|
|
||||||
action := strings.ToLower(ActionPlayer["Action"])
|
|
||||||
if slices.Contains([]string{PlayerActionConnect, PlayerActionDisconnect, PlayerActionSpawn}, action) {
|
|
||||||
w.Players = append(w.Players, PlayerConnection{
|
|
||||||
Player: strings.TrimSpace(ActionPlayer["Username"]),
|
|
||||||
XUID: strings.TrimSpace(ActionPlayer["Xuid"]),
|
|
||||||
Action: action,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Port listen
|
|
||||||
func (w *Handlers) ParsePort(logline string) {
|
|
||||||
for _, reg := range MojangPort {
|
|
||||||
if reg.MatchString(logline) {
|
|
||||||
infoPort := reg.FindAllGroups(logline)
|
|
||||||
var port uint16
|
|
||||||
if _, err := fmt.Sscan(infoPort["Port"], &port); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if port ared added to slice
|
|
||||||
if !slices.Contains(w.Ports, port) {
|
|
||||||
w.Ports = append(w.Ports, port)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse log and register on handlers
|
|
||||||
func (w *Handlers) RegisterScan(log io.ReadCloser) {
|
|
||||||
defer log.Close()
|
|
||||||
logScan := bufio.NewScanner(log)
|
|
||||||
for logScan.Scan() {
|
|
||||||
logLine := logScan.Text()
|
|
||||||
go w.ParseStarted(logLine)
|
|
||||||
go w.ParsePlayer(logLine)
|
|
||||||
go w.ParsePort(logLine)
|
|
||||||
}
|
|
||||||
}
|
|
137
java/log.go
137
java/log.go
@ -1,137 +0,0 @@
|
|||||||
package java
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"slices"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"sirherobrine23.com.br/go-bds/go-bds/mclog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = mclog.RegisterNewParse(NewLogParse{})
|
|
||||||
|
|
||||||
type NewLogParse struct{}
|
|
||||||
|
|
||||||
func (NewLogParse) String() string { return "mojang/java" }
|
|
||||||
func (NewLogParse) New() (mclog.ServerParse, error) { return &LogerParse{}, nil }
|
|
||||||
|
|
||||||
type LogerParse struct {
|
|
||||||
local mclog.Insights
|
|
||||||
}
|
|
||||||
|
|
||||||
func (loger LogerParse) Insight() *mclog.Insights { return &loger.local }
|
|
||||||
func (loger *LogerParse) Detect(log io.ReadSeeker) error {
|
|
||||||
loger.local = mclog.Insights{
|
|
||||||
ID: "mojang/java",
|
|
||||||
Name: "java",
|
|
||||||
Type: "Server log",
|
|
||||||
Title: "java",
|
|
||||||
Version: "unknown",
|
|
||||||
Analysis: map[mclog.LogLevel][]*mclog.InsightsAnalysis{},
|
|
||||||
}
|
|
||||||
|
|
||||||
scan := bufio.NewScanner(log)
|
|
||||||
isValid, Analysis, logLevel, err := false, (*mclog.InsightsAnalysis)(nil), mclog.LogUnknown, error(nil)
|
|
||||||
for scan.Scan() {
|
|
||||||
add := false
|
|
||||||
text := scan.Text()
|
|
||||||
if strings.HasPrefix(text, "Unpacking") || strings.HasPrefix(text, "Starting") {
|
|
||||||
continue
|
|
||||||
} else if !isValid {
|
|
||||||
if text[0] != '[' {
|
|
||||||
return mclog.ErrSkipParse
|
|
||||||
}
|
|
||||||
isValid = true
|
|
||||||
}
|
|
||||||
if text[0] != '[' {
|
|
||||||
if Analysis == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
Analysis.Entry.Lines = append(Analysis.Entry.Lines, mclog.EntryLine{
|
|
||||||
Content: text,
|
|
||||||
Numbers: strings.Count(text, "") - len(strings.Split(text, " ")),
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
Analysis = &mclog.InsightsAnalysis{
|
|
||||||
Value: text,
|
|
||||||
Entry: mclog.AnalysisEntry{
|
|
||||||
Lines: []mclog.EntryLine{
|
|
||||||
{
|
|
||||||
Content: text,
|
|
||||||
Numbers: strings.Count(text, "") - len(strings.Split(text, " ")),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
prefixSplited := [3]string(strings.SplitAfterN(text, "]", 3))
|
|
||||||
prefixSplited[0] = strings.Replace(strings.Replace(strings.TrimSpace(prefixSplited[0][1:]), "[", "", 1), "]", "", 1)
|
|
||||||
prefixSplited[1] = strings.Replace(strings.Replace(strings.TrimSpace(prefixSplited[1][1:]), "[", "", 1), "]", "", 1)
|
|
||||||
prefixSplited[2] = strings.TrimSpace(prefixSplited[2][1:])
|
|
||||||
Analysis.Message = prefixSplited[2]
|
|
||||||
Analysis.Entry.Prefix = fmt.Sprintf("[%s] [%s]", prefixSplited[0], prefixSplited[1])
|
|
||||||
if len(strings.Split(prefixSplited[0], ":")) != 3 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasSuffix(prefixSplited[1], "INFO") {
|
|
||||||
logLevel = mclog.LogInfo
|
|
||||||
} else if strings.HasSuffix(prefixSplited[1], "WARN") {
|
|
||||||
logLevel = mclog.LogWarn
|
|
||||||
Analysis.Label = "Error"
|
|
||||||
add = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if Analysis.Entry.EntryTime, err = time.ParseInLocation(time.TimeOnly, prefixSplited[0], time.Local); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
Analysis.Entry.EntryTime = Analysis.Entry.EntryTime.UTC()
|
|
||||||
contentExplode := strings.Fields(prefixSplited[2])
|
|
||||||
|
|
||||||
switch contentExplode[0] {
|
|
||||||
case "RCON":
|
|
||||||
if contentExplode[len(contentExplode)-2] == "on" {
|
|
||||||
add = true
|
|
||||||
Analysis.Label = "RCON"
|
|
||||||
Analysis.Value = contentExplode[len(contentExplode)-1]
|
|
||||||
}
|
|
||||||
case "Starting":
|
|
||||||
if len(contentExplode) <= 3 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch contentExplode[len(contentExplode)-2] {
|
|
||||||
case "version":
|
|
||||||
add = true
|
|
||||||
version := contentExplode[len(contentExplode)-1]
|
|
||||||
loger.local.Version = version
|
|
||||||
Analysis.Value = version
|
|
||||||
Analysis.Label = "Java version"
|
|
||||||
case "on":
|
|
||||||
add = true
|
|
||||||
Analysis.Label = "Port"
|
|
||||||
Analysis.Value = contentExplode[len(contentExplode)-1][2:]
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
switch contentExplode[len(contentExplode)-1] {
|
|
||||||
case "game":
|
|
||||||
if slices.Contains([]string{"left", "joined"}, contentExplode[len(contentExplode)-3]) {
|
|
||||||
add = true
|
|
||||||
Analysis.Message = "Player status"
|
|
||||||
Analysis.Label = contentExplode[len(contentExplode)-3]
|
|
||||||
Analysis.Value = prefixSplited[2][:strings.LastIndex(prefixSplited[2], contentExplode[len(contentExplode)-3])-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if add {
|
|
||||||
Analysis.Counter = len(Analysis.Entry.Lines)
|
|
||||||
loger.local.Analysis[logLevel] = append(loger.local.Analysis[logLevel], Analysis)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
35
logs/bedrock/1.19.41.01.txt
Normal file
35
logs/bedrock/1.19.41.01.txt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
NO LOG FILE! - setting up server logging...
|
||||||
|
[2022-11-16 19:34:11:606 INFO] Starting Server
|
||||||
|
[2022-11-16 19:34:11:606 INFO] Version 1.19.41.01
|
||||||
|
[2022-11-16 19:34:11:606 INFO] Session ID d914c8d5-2ad1-46fd-b213-e76ed4e6caca
|
||||||
|
[2022-11-16 19:34:11:606 INFO] Level Name: Sirherobrine23
|
||||||
|
[2022-11-16 19:34:11:609 INFO] Game mode: 0 Survival
|
||||||
|
[2022-11-16 19:34:11:609 INFO] Difficulty: 2 NORMAL
|
||||||
|
[2022-11-16 19:34:11:729 INFO] opening worlds/Sirherobrine23/db
|
||||||
|
[2022-11-16 19:34:12:336 INFO] IPv4 supported, port: 19132
|
||||||
|
[2022-11-16 19:34:12:337 INFO] IPv6 supported, port: 19133
|
||||||
|
[2022-11-16 19:34:13:002 INFO] Server started.
|
||||||
|
[2022-11-16 19:34:13:008 INFO] Please note that LAN discovery will not function for this server.
|
||||||
|
[2022-11-16 19:34:13:008 INFO] Server IP must be specified in Servers tab in game.
|
||||||
|
[2022-11-16 19:34:13:052 INFO] ================ TELEMETRY MESSAGE ===================
|
||||||
|
[2022-11-16 19:34:13:052 INFO] Server Telemetry is currently not enabled.
|
||||||
|
[2022-11-16 19:34:13:052 INFO] Enabling this telemetry helps us improve the game.
|
||||||
|
[2022-11-16 19:34:13:052 INFO]
|
||||||
|
[2022-11-16 19:34:13:052 INFO] To enable this feature, add the line 'emit-server-telemetry=true'
|
||||||
|
[2022-11-16 19:34:13:052 INFO] to the server.properties file in the handheld/src-server directory
|
||||||
|
[2022-11-16 19:34:13:052 INFO] ======================================================
|
||||||
|
[2022-11-16 19:55:44:503 INFO] Player connected: Sirherobrine, xuid: 2535413418839840
|
||||||
|
[2022-11-16 19:55:49:400 INFO] Player Spawned: Sirherobrine xuid: 2535413418839840
|
||||||
|
[2022-11-16 19:56:59:378 INFO] Player disconnected: Sirherobrine, xuid: 2535413418839840
|
||||||
|
[2022-11-16 20:01:48:937 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-16 20:07:48:959 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-19 19:23:22:600 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-19 19:29:22:601 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-19 19:35:22:602 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-19 19:41:23:746 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-19 19:47:23:746 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-19 19:53:23:747 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-19 19:59:23:748 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-19 20:05:24:904 INFO] Running AutoCompaction...
|
||||||
|
[2022-11-19 20:07:15:776 INFO] Player connected: Sirherobrine, xuid: 2535413418839840
|
||||||
|
[2022-11-19 20:07:30:911 INFO] Player Spawned: Sirherobrine xuid: 2535413418839840
|
28
logs/bedrock/1.21.70-beta25.txt
Normal file
28
logs/bedrock/1.21.70-beta25.txt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
NO LOG FILE! - setting up server logging...
|
||||||
|
[2025-03-02 18:47:06:641 INFO] Starting Server
|
||||||
|
[2025-03-02 18:47:06:641 INFO] Version: 1.21.70-beta25
|
||||||
|
[2025-03-02 18:47:06:641 INFO] Session ID: 5780f638-3db3-41b8-8ec8-7fa0fe39c0ca
|
||||||
|
[2025-03-02 18:47:06:641 INFO] Build ID: 31345670
|
||||||
|
[2025-03-02 18:47:06:641 INFO] Branch: r/21_u7
|
||||||
|
[2025-03-02 18:47:06:641 INFO] Commit ID: 7ca47dbf5277ac770e27cf3b41bb3e6d0ca27afa
|
||||||
|
[2025-03-02 18:47:06:641 INFO] Configuration: Publish
|
||||||
|
[2025-03-02 18:47:06:641 INFO] Level Name: Bedrock level
|
||||||
|
[2025-03-02 18:47:06:642 INFO] No CDN config file found for dedicated server
|
||||||
|
[2025-03-02 18:47:06:642 INFO] Game mode: 0 Survival
|
||||||
|
[2025-03-02 18:47:06:642 INFO] Difficulty: 1 EASY
|
||||||
|
[2025-03-02 18:47:06:644 INFO] Content logging to console is enabled.
|
||||||
|
[2025-03-02 18:47:07:160 INFO] Opening level 'worlds/Bedrock level/db'
|
||||||
|
[2025-03-02 18:47:07:175 INFO] [SERVER] Pack Stack - None
|
||||||
|
[2025-03-02 18:47:08:045 INFO] IPv4 supported, port: 19132: Used for gameplay and LAN discovery
|
||||||
|
[2025-03-02 18:47:08:045 INFO] IPv6 supported, port: 19133: Used for gameplay
|
||||||
|
[2025-03-02 18:47:08:083 INFO] Server started.
|
||||||
|
[2025-03-02 18:47:08:083 INFO] ================ TELEMETRY MESSAGE ===================
|
||||||
|
[2025-03-02 18:47:08:083 INFO] Server Telemetry is currently not enabled.
|
||||||
|
[2025-03-02 18:47:08:083 INFO] Enabling this telemetry helps us improve the game.
|
||||||
|
[2025-03-02 18:47:08:083 INFO]
|
||||||
|
[2025-03-02 18:47:08:083 INFO] To enable this feature, add the line 'emit-server-telemetry=true'
|
||||||
|
[2025-03-02 18:47:08:083 INFO] to the server.properties file in the handheld/src-server directory
|
||||||
|
[2025-03-02 18:47:08:083 INFO] ======================================================
|
||||||
|
[2025-03-02 18:47:15:702 INFO] Server stop requested.
|
||||||
|
[2025-03-02 18:47:15:704 INFO] Stopping server...
|
||||||
|
Quit correctly
|
16
logs/bedrock/1.6.1.0.txt
Normal file
16
logs/bedrock/1.6.1.0.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
NO LOG FILE! - setting up server logging...
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Starting Server
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Version 1.6.1.0
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Level Name: Bedrock level
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:13 ERROR] Error opening whitelist file: whitelist.json
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:13 ERROR] Error opening ops file: ops.json
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Game mode: 0 Survival
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Difficulty: 1 EASY
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:13 INFO] IPv4 supported, port: 19132
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:13 INFO] IPv6 supported, port: 19133
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:14 INFO] Listening on IPv6 port: 19133
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:14 INFO] Listening on IPv4 port: 19132
|
||||||
|
NO LOG FILE! - [2025-01-19 23:35:18 INFO] Player connected: 2535413418839840
|
||||||
|
NO LOG FILE! - [2025-01-19 23:38:54 INFO] Player disconnected: 2535413418839840
|
||||||
|
NO LOG FILE! - [2025-01-19 23:40:13 INFO] Player connected:
|
||||||
|
NO LOG FILE! - [2025-01-19 23:40:54 INFO] Player disconnected:
|
221
logs/bedrock/bedrock.go
Normal file
221
logs/bedrock/bedrock.go
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
package bedrock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"net/netip"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/logs"
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/utils/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ = logs.RegisterParse[*BedrockParse]("mojang/bedrock")
|
||||||
|
|
||||||
|
_ logs.Log = &BedrockParse{}
|
||||||
|
_ logs.Player = &BedrockPlayer{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type BedrockPlayer struct {
|
||||||
|
Username string `json:"player"` // Player username
|
||||||
|
Actioned logs.Action `json:"action"` // Action type
|
||||||
|
Timed time.Time `json:"time"` // Action time
|
||||||
|
PlayerXUID int64 `json:"xuid"` // Player xuid
|
||||||
|
PFID string `json:"pfid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (player BedrockPlayer) Name() string { return player.Username }
|
||||||
|
func (player BedrockPlayer) Action() logs.Action { return player.Actioned }
|
||||||
|
func (player BedrockPlayer) Time() time.Time { return player.Timed }
|
||||||
|
func (player BedrockPlayer) XUID() int64 { return player.PlayerXUID }
|
||||||
|
|
||||||
|
type BedrockParse struct {
|
||||||
|
LastCompaction time.Time `json:"last_world_compaction"` // Last world size reduce
|
||||||
|
SessionID string `json:"session"` // Server session
|
||||||
|
CommitID string `json:"commit"` // commit hash
|
||||||
|
Branch string `json:"branch"` // Server Branch build
|
||||||
|
ServerPlaform *logs.Server `json:"info"` // Basic server info
|
||||||
|
Players map[string][]logs.Player `json:"players"` // Players
|
||||||
|
Errs []error `json:"errors"`
|
||||||
|
Warngs []error `json:"warnings"`
|
||||||
|
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bedrock BedrockParse) Server() *logs.Server { return bedrock.ServerPlaform }
|
||||||
|
func (bedrock BedrockParse) Errors() []error { return bedrock.Errs }
|
||||||
|
func (bedrock BedrockParse) Warnings() []error { return bedrock.Warngs }
|
||||||
|
func (bedrock BedrockParse) GetPlayer(name string) (player []logs.Player, ok bool) {
|
||||||
|
player, ok = bedrock.Players[name]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bedrock *BedrockParse) ParseTime(current time.Time, log io.Reader) error {
|
||||||
|
return bedrock.Parse(log)
|
||||||
|
}
|
||||||
|
func (bedrock *BedrockParse) Parse(log io.Reader) error {
|
||||||
|
bedrock.ServerPlaform = &logs.Server{Platform: "mojang/bedrock", Ports: []*logs.Port{}} // Init info
|
||||||
|
bedrock.Errs, bedrock.Warngs = []error{}, []error{}
|
||||||
|
bedrock.Players = map[string][]logs.Player{}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(log)
|
||||||
|
for scanner.Scan() {
|
||||||
|
text := scanner.Text()
|
||||||
|
text = strings.TrimPrefix(text, "NO LOG FILE! - ")
|
||||||
|
if strings.HasPrefix(text, "setting up server") || strings.HasPrefix(text, "Quit correctly") || text == "" {
|
||||||
|
continue
|
||||||
|
} else if !(strings.Contains(text, "]")) {
|
||||||
|
return logs.ErrSkipPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixEnd := strings.Index(text, "]")
|
||||||
|
prefix := strings.TrimSpace(strings.TrimSuffix(text[strings.Index(text, "[")+1:prefixEnd], "INFO"))
|
||||||
|
line := strings.TrimSpace(text[prefixEnd+1:])
|
||||||
|
if line == "" {
|
||||||
|
continue // skip
|
||||||
|
} else if len(prefix) < 19 {
|
||||||
|
return logs.ErrSkipPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
err := error(nil)
|
||||||
|
if strings.HasSuffix(prefix, "ERROR") || strings.HasSuffix(prefix, "WARN") {
|
||||||
|
bedrock.Errs = append(bedrock.Errs, &logs.ErrorReference{LogLevel: 1, FistLine: line})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date
|
||||||
|
if strings.Count(prefix, ":") == 3 {
|
||||||
|
lastColonIndex := strings.LastIndex(prefix, ":")
|
||||||
|
prefix = prefix[:lastColonIndex] + "." + prefix[lastColonIndex+1:]
|
||||||
|
}
|
||||||
|
EntryTime, err := time.Parse("2006-01-02 15:04:05.999", prefix)
|
||||||
|
if err != nil {
|
||||||
|
if EntryTime, err = time.Parse("2006-01-02 15:04:05", prefix[:19]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EntryTime = EntryTime.UTC() // Convert to UTC time
|
||||||
|
|
||||||
|
explodeString := slice.Slice[string](strings.Fields(line))
|
||||||
|
switch explodeString.At(0) {
|
||||||
|
case "Server":
|
||||||
|
if strings.Contains(text, "started") {
|
||||||
|
bedrock.ServerPlaform.Started = EntryTime
|
||||||
|
}
|
||||||
|
case "Session":
|
||||||
|
if explodeString.At(1) == "ID" {
|
||||||
|
bedrock.SessionID = explodeString.At(2)
|
||||||
|
}
|
||||||
|
case "Branch:":
|
||||||
|
bedrock.Branch = explodeString.At(1)
|
||||||
|
case "Commit":
|
||||||
|
bedrock.CommitID = explodeString.At(2)
|
||||||
|
case "Running":
|
||||||
|
if strings.HasPrefix(explodeString.At(1), "AutoCompaction") {
|
||||||
|
bedrock.LastCompaction = EntryTime
|
||||||
|
}
|
||||||
|
case "Version", "Version:":
|
||||||
|
if len(explodeString) >= 2 {
|
||||||
|
bedrock.ServerPlaform.Version = explodeString.At(-1)
|
||||||
|
}
|
||||||
|
case "IPv6", "IPv4", "Listening":
|
||||||
|
if explodeString.At(-2) == "port:" {
|
||||||
|
protoLocation := 0
|
||||||
|
if explodeString.At(0) == "Listening" {
|
||||||
|
protoLocation = len(explodeString) - 3
|
||||||
|
}
|
||||||
|
|
||||||
|
port, err := strconv.ParseInt(explodeString.At(-1), 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := netip.AddrPortFrom(netip.IPv4Unspecified(), uint16(port))
|
||||||
|
if explodeString[protoLocation] == "IPv6" {
|
||||||
|
addr = netip.AddrPortFrom(netip.IPv6Unspecified(), uint16(port))
|
||||||
|
}
|
||||||
|
|
||||||
|
bedrock.ServerPlaform.Ports = append(bedrock.ServerPlaform.Ports, &logs.Port{
|
||||||
|
AddrPort: addr,
|
||||||
|
From: "server",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
case "Player":
|
||||||
|
// Player connected:
|
||||||
|
// Player disconnected:
|
||||||
|
// Player connected: 2535413418839840
|
||||||
|
// Player disconnected: 2535413418839840
|
||||||
|
|
||||||
|
// Player connected: Sirherobrine, xuid: 2535413418839840
|
||||||
|
// Player Spawned: Sirherobrine xuid: 2535413418839840
|
||||||
|
// Player disconnected: Sirherobrine, xuid: 2535413418839840
|
||||||
|
|
||||||
|
// Player Connected: nod dd, xuid: , pfid: c31902da495f4549
|
||||||
|
// Player Spawned: nod dd xuid: , pfid: c31902da495f4549
|
||||||
|
// Player disconnected: nod dd, xuid: , pfid: c31902da495f4549
|
||||||
|
if !slices.Contains([]string{"connected:", "spawned:", "disconnected:"}, strings.ToLower(explodeString.At(1))) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var player, xuid, pfid string
|
||||||
|
if player = strings.TrimSpace(line[strings.Index(line, explodeString.At(1))+len(explodeString.At(1)):]); player == "" {
|
||||||
|
// Old versions of Minecraft Bedrock Server (before 1.6.0)
|
||||||
|
// did not return the names of those who were not logged in
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(player, ", xuid:") {
|
||||||
|
xuidd := strings.SplitN(player, ", xuid:", 2)
|
||||||
|
player = strings.TrimSpace(xuidd[0])
|
||||||
|
xuid = strings.TrimSpace(xuidd[1])
|
||||||
|
if strings.Contains(xuid, ", pfid:") {
|
||||||
|
pdis := strings.SplitN(xuid, ", pfid:", 2)
|
||||||
|
xuid = strings.TrimSpace(pdis[0])
|
||||||
|
pfid = strings.TrimSpace(pdis[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(player, "xuid:") {
|
||||||
|
xuid = player[strings.LastIndex(player, "xuid:")+5:]
|
||||||
|
player = player[:strings.LastIndex(player, "xuid:")-1]
|
||||||
|
if player[len(player)-1] == ',' {
|
||||||
|
player = player[:len(player)-1]
|
||||||
|
}
|
||||||
|
if strings.Contains(xuid, ",") {
|
||||||
|
xuid = xuid[:strings.Index(player, ",")]
|
||||||
|
}
|
||||||
|
xuid = strings.TrimSpace(xuid)
|
||||||
|
player = strings.TrimSpace(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
level := logs.Action(0)
|
||||||
|
switch strings.ToLower(explodeString.At(1)) {
|
||||||
|
case "disconnected:":
|
||||||
|
level = logs.Disconnect
|
||||||
|
case "connected:":
|
||||||
|
level = logs.Connect
|
||||||
|
case "spawned:":
|
||||||
|
level = logs.Spawned
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := bedrock.Players[player]; !ok {
|
||||||
|
bedrock.Players[player] = []logs.Player{}
|
||||||
|
}
|
||||||
|
|
||||||
|
xuidID, _ := strconv.ParseInt(xuid, 10, 64) // Convert xuid string to XUID int
|
||||||
|
bedrock.Players[player] = append(bedrock.Players[player], BedrockPlayer{
|
||||||
|
Username: player,
|
||||||
|
Actioned: level,
|
||||||
|
Timed: EntryTime,
|
||||||
|
PlayerXUID: xuidID,
|
||||||
|
PFID: pfid,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scanner.Err()
|
||||||
|
}
|
44
logs/bedrock/bedrock_test.go
Normal file
44
logs/bedrock/bedrock_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package bedrock
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed 1.19.41.01.txt
|
||||||
|
StaticLogFileBedrock1 string
|
||||||
|
//go:embed 1.6.1.0.txt
|
||||||
|
StaticLogFileBedrock2 string
|
||||||
|
//go:embed 1.21.70-beta25.txt
|
||||||
|
StaticLogFileBedrock3 string
|
||||||
|
)
|
||||||
|
|
||||||
|
func testPrintLog(t *testing.T, textPrint string, log *BedrockParse) {
|
||||||
|
d, _ := json.MarshalIndent(log, "", " ")
|
||||||
|
t.Logf(textPrint, string(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDetectAndParseBedrock(t *testing.T) {
|
||||||
|
parsedLog, err := &BedrockParse{}, error(nil)
|
||||||
|
if err = parsedLog.Parse(strings.NewReader(StaticLogFileBedrock1)); err != nil {
|
||||||
|
t.Errorf("Cannot parse bedrock log 1: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
testPrintLog(t, "Parsed log bedrock Static 1:\n%s", parsedLog)
|
||||||
|
|
||||||
|
if err = parsedLog.Parse(strings.NewReader(StaticLogFileBedrock2)); err != nil {
|
||||||
|
t.Errorf("Cannot parse bedrock log 2: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
testPrintLog(t, "Parsed log bedrock Static 2:\n%s", parsedLog)
|
||||||
|
|
||||||
|
if err = parsedLog.Parse(strings.NewReader(StaticLogFileBedrock3)); err != nil {
|
||||||
|
t.Errorf("Cannot parse bedrock log 3: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
testPrintLog(t, "Parsed log bedrock Static 3:\n%s", parsedLog)
|
||||||
|
}
|
104
logs/java/1.21.4.txt
Normal file
104
logs/java/1.21.4.txt
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
Unpacking 1.21.4/server-1.21.4.jar (versions:1.21.4) to versions/1.21.4/server-1.21.4.jar
|
||||||
|
Unpacking com/fasterxml/jackson/core/jackson-annotations/2.13.4/jackson-annotations-2.13.4.jar (libraries:com.fasterxml.jackson.core:jackson-annotations:2.13.4) to libraries/com/fasterxml/jackson/core/jackson-annotations/2.13.4/jackson-annotations-2.13.4.jar
|
||||||
|
Unpacking com/fasterxml/jackson/core/jackson-core/2.13.4/jackson-core-2.13.4.jar (libraries:com.fasterxml.jackson.core:jackson-core:2.13.4) to libraries/com/fasterxml/jackson/core/jackson-core/2.13.4/jackson-core-2.13.4.jar
|
||||||
|
Unpacking com/fasterxml/jackson/core/jackson-databind/2.13.4.2/jackson-databind-2.13.4.2.jar (libraries:com.fasterxml.jackson.core:jackson-databind:2.13.4.2) to libraries/com/fasterxml/jackson/core/jackson-databind/2.13.4.2/jackson-databind-2.13.4.2.jar
|
||||||
|
Unpacking com/github/oshi/oshi-core/6.6.5/oshi-core-6.6.5.jar (libraries:com.github.oshi:oshi-core:6.6.5) to libraries/com/github/oshi/oshi-core/6.6.5/oshi-core-6.6.5.jar
|
||||||
|
Unpacking com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar (libraries:com.github.stephenc.jcip:jcip-annotations:1.0-1) to libraries/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar
|
||||||
|
Unpacking com/google/code/gson/gson/2.11.0/gson-2.11.0.jar (libraries:com.google.code.gson:gson:2.11.0) to libraries/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar
|
||||||
|
Unpacking com/google/guava/failureaccess/1.0.2/failureaccess-1.0.2.jar (libraries:com.google.guava:failureaccess:1.0.2) to libraries/com/google/guava/failureaccess/1.0.2/failureaccess-1.0.2.jar
|
||||||
|
Unpacking com/google/guava/guava/33.3.1-jre/guava-33.3.1-jre.jar (libraries:com.google.guava:guava:33.3.1-jre) to libraries/com/google/guava/guava/33.3.1-jre/guava-33.3.1-jre.jar
|
||||||
|
Unpacking com/microsoft/azure/msal4j/1.17.2/msal4j-1.17.2.jar (libraries:com.microsoft.azure:msal4j:1.17.2) to libraries/com/microsoft/azure/msal4j/1.17.2/msal4j-1.17.2.jar
|
||||||
|
Unpacking com/mojang/authlib/6.0.57/authlib-6.0.57.jar (libraries:com.mojang:authlib:6.0.57) to libraries/com/mojang/authlib/6.0.57/authlib-6.0.57.jar
|
||||||
|
Unpacking com/mojang/brigadier/1.3.10/brigadier-1.3.10.jar (libraries:com.mojang:brigadier:1.3.10) to libraries/com/mojang/brigadier/1.3.10/brigadier-1.3.10.jar
|
||||||
|
Unpacking com/mojang/datafixerupper/8.0.16/datafixerupper-8.0.16.jar (libraries:com.mojang:datafixerupper:8.0.16) to libraries/com/mojang/datafixerupper/8.0.16/datafixerupper-8.0.16.jar
|
||||||
|
Unpacking com/mojang/jtracy/1.0.29/jtracy-1.0.29.jar (libraries:com.mojang:jtracy:1.0.29) to libraries/com/mojang/jtracy/1.0.29/jtracy-1.0.29.jar
|
||||||
|
Unpacking com/mojang/logging/1.5.10/logging-1.5.10.jar (libraries:com.mojang:logging:1.5.10) to libraries/com/mojang/logging/1.5.10/logging-1.5.10.jar
|
||||||
|
Unpacking com/nimbusds/content-type/2.3/content-type-2.3.jar (libraries:com.nimbusds:content-type:2.3) to libraries/com/nimbusds/content-type/2.3/content-type-2.3.jar
|
||||||
|
Unpacking com/nimbusds/lang-tag/1.7/lang-tag-1.7.jar (libraries:com.nimbusds:lang-tag:1.7) to libraries/com/nimbusds/lang-tag/1.7/lang-tag-1.7.jar
|
||||||
|
Unpacking com/nimbusds/nimbus-jose-jwt/9.40/nimbus-jose-jwt-9.40.jar (libraries:com.nimbusds:nimbus-jose-jwt:9.40) to libraries/com/nimbusds/nimbus-jose-jwt/9.40/nimbus-jose-jwt-9.40.jar
|
||||||
|
Unpacking com/nimbusds/oauth2-oidc-sdk/11.18/oauth2-oidc-sdk-11.18.jar (libraries:com.nimbusds:oauth2-oidc-sdk:11.18) to libraries/com/nimbusds/oauth2-oidc-sdk/11.18/oauth2-oidc-sdk-11.18.jar
|
||||||
|
Unpacking commons-io/commons-io/2.17.0/commons-io-2.17.0.jar (libraries:commons-io:commons-io:2.17.0) to libraries/commons-io/commons-io/2.17.0/commons-io-2.17.0.jar
|
||||||
|
Unpacking io/netty/netty-buffer/4.1.115.Final/netty-buffer-4.1.115.Final.jar (libraries:io.netty:netty-buffer:4.1.115.Final) to libraries/io/netty/netty-buffer/4.1.115.Final/netty-buffer-4.1.115.Final.jar
|
||||||
|
Unpacking io/netty/netty-codec/4.1.115.Final/netty-codec-4.1.115.Final.jar (libraries:io.netty:netty-codec:4.1.115.Final) to libraries/io/netty/netty-codec/4.1.115.Final/netty-codec-4.1.115.Final.jar
|
||||||
|
Unpacking io/netty/netty-common/4.1.115.Final/netty-common-4.1.115.Final.jar (libraries:io.netty:netty-common:4.1.115.Final) to libraries/io/netty/netty-common/4.1.115.Final/netty-common-4.1.115.Final.jar
|
||||||
|
Unpacking io/netty/netty-handler/4.1.115.Final/netty-handler-4.1.115.Final.jar (libraries:io.netty:netty-handler:4.1.115.Final) to libraries/io/netty/netty-handler/4.1.115.Final/netty-handler-4.1.115.Final.jar
|
||||||
|
Unpacking io/netty/netty-resolver/4.1.115.Final/netty-resolver-4.1.115.Final.jar (libraries:io.netty:netty-resolver:4.1.115.Final) to libraries/io/netty/netty-resolver/4.1.115.Final/netty-resolver-4.1.115.Final.jar
|
||||||
|
Unpacking io/netty/netty-transport/4.1.115.Final/netty-transport-4.1.115.Final.jar (libraries:io.netty:netty-transport:4.1.115.Final) to libraries/io/netty/netty-transport/4.1.115.Final/netty-transport-4.1.115.Final.jar
|
||||||
|
Unpacking io/netty/netty-transport-classes-epoll/4.1.115.Final/netty-transport-classes-epoll-4.1.115.Final.jar (libraries:io.netty:netty-transport-classes-epoll:4.1.115.Final) to libraries/io/netty/netty-transport-classes-epoll/4.1.115.Final/netty-transport-classes-epoll-4.1.115.Final.jar
|
||||||
|
Unpacking io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-x86_64.jar (libraries:io.netty:netty-transport-native-epoll:4.1.115.Final:linux-x86_64) to libraries/io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-x86_64.jar
|
||||||
|
Unpacking io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-aarch_64.jar (libraries:io.netty:netty-transport-native-epoll:4.1.115.Final:linux-aarch_64) to libraries/io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-aarch_64.jar
|
||||||
|
Unpacking io/netty/netty-transport-native-unix-common/4.1.115.Final/netty-transport-native-unix-common-4.1.115.Final.jar (libraries:io.netty:netty-transport-native-unix-common:4.1.115.Final) to libraries/io/netty/netty-transport-native-unix-common/4.1.115.Final/netty-transport-native-unix-common-4.1.115.Final.jar
|
||||||
|
Unpacking it/unimi/dsi/fastutil/8.5.15/fastutil-8.5.15.jar (libraries:it.unimi.dsi:fastutil:8.5.15) to libraries/it/unimi/dsi/fastutil/8.5.15/fastutil-8.5.15.jar
|
||||||
|
Unpacking net/java/dev/jna/jna/5.15.0/jna-5.15.0.jar (libraries:net.java.dev.jna:jna:5.15.0) to libraries/net/java/dev/jna/jna/5.15.0/jna-5.15.0.jar
|
||||||
|
Unpacking net/java/dev/jna/jna-platform/5.15.0/jna-platform-5.15.0.jar (libraries:net.java.dev.jna:jna-platform:5.15.0) to libraries/net/java/dev/jna/jna-platform/5.15.0/jna-platform-5.15.0.jar
|
||||||
|
Unpacking net/minidev/accessors-smart/2.5.1/accessors-smart-2.5.1.jar (libraries:net.minidev:accessors-smart:2.5.1) to libraries/net/minidev/accessors-smart/2.5.1/accessors-smart-2.5.1.jar
|
||||||
|
Unpacking net/minidev/json-smart/2.5.1/json-smart-2.5.1.jar (libraries:net.minidev:json-smart:2.5.1) to libraries/net/minidev/json-smart/2.5.1/json-smart-2.5.1.jar
|
||||||
|
Unpacking net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar (libraries:net.sf.jopt-simple:jopt-simple:5.0.4) to libraries/net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar
|
||||||
|
Unpacking org/apache/commons/commons-lang3/3.17.0/commons-lang3-3.17.0.jar (libraries:org.apache.commons:commons-lang3:3.17.0) to libraries/org/apache/commons/commons-lang3/3.17.0/commons-lang3-3.17.0.jar
|
||||||
|
Unpacking org/apache/logging/log4j/log4j-api/2.24.1/log4j-api-2.24.1.jar (libraries:org.apache.logging.log4j:log4j-api:2.24.1) to libraries/org/apache/logging/log4j/log4j-api/2.24.1/log4j-api-2.24.1.jar
|
||||||
|
Unpacking org/apache/logging/log4j/log4j-core/2.24.1/log4j-core-2.24.1.jar (libraries:org.apache.logging.log4j:log4j-core:2.24.1) to libraries/org/apache/logging/log4j/log4j-core/2.24.1/log4j-core-2.24.1.jar
|
||||||
|
Unpacking org/apache/logging/log4j/log4j-slf4j2-impl/2.24.1/log4j-slf4j2-impl-2.24.1.jar (libraries:org.apache.logging.log4j:log4j-slf4j2-impl:2.24.1) to libraries/org/apache/logging/log4j/log4j-slf4j2-impl/2.24.1/log4j-slf4j2-impl-2.24.1.jar
|
||||||
|
Unpacking org/joml/joml/1.10.8/joml-1.10.8.jar (libraries:org.joml:joml:1.10.8) to libraries/org/joml/joml/1.10.8/joml-1.10.8.jar
|
||||||
|
Unpacking org/lz4/lz4-java/1.8.0/lz4-java-1.8.0.jar (libraries:org.lz4:lz4-java:1.8.0) to libraries/org/lz4/lz4-java/1.8.0/lz4-java-1.8.0.jar
|
||||||
|
Unpacking org/ow2/asm/asm/9.6/asm-9.6.jar (libraries:org.ow2.asm:asm:9.6) to libraries/org/ow2/asm/asm/9.6/asm-9.6.jar
|
||||||
|
Unpacking org/slf4j/slf4j-api/2.0.16/slf4j-api-2.0.16.jar (libraries:org.slf4j:slf4j-api:2.0.16) to libraries/org/slf4j/slf4j-api/2.0.16/slf4j-api-2.0.16.jar
|
||||||
|
Starting net.minecraft.server.Main
|
||||||
|
[21:40:55] [ServerMain/INFO]: Environment: Environment[sessionHost=https://sessionserver.mojang.com, servicesHost=https://api.minecraftservices.com, name=PROD]
|
||||||
|
[21:40:59] [ServerMain/INFO]: No existing world data, creating new world
|
||||||
|
[21:41:01] [ServerMain/INFO]: Loaded 1370 recipes
|
||||||
|
[21:41:01] [ServerMain/INFO]: Loaded 1481 advancements
|
||||||
|
[21:41:01] [Server thread/INFO]: Starting minecraft server version 1.21.4
|
||||||
|
[21:41:01] [Server thread/INFO]: Loading properties
|
||||||
|
[21:41:01] [Server thread/INFO]: Default game type: SURVIVAL
|
||||||
|
[21:41:01] [Server thread/INFO]: Generating keypair
|
||||||
|
[21:41:01] [Server thread/INFO]: Starting Minecraft server on *:25565
|
||||||
|
[21:41:02] [Server thread/INFO]: Using epoll channel type
|
||||||
|
[21:41:02] [Server thread/INFO]: Preparing level "world"
|
||||||
|
[21:41:22] [Server thread/INFO]: Preparing start region for dimension minecraft:overworld
|
||||||
|
[21:41:23] [Worker-Main-2/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:23] [Worker-Main-2/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:24] [Worker-Main-2/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:24] [Worker-Main-3/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:24] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:25] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:25] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:26] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:26] [Worker-Main-3/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:27] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:27] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:28] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:28] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
||||||
|
[21:41:29] [Worker-Main-3/INFO]: Preparing spawn area: 8%
|
||||||
|
[21:41:30] [Worker-Main-2/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:30] [Worker-Main-2/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:30] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:31] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:31] [Worker-Main-3/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:32] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:32] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:33] [Worker-Main-3/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:33] [Worker-Main-3/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:34] [Worker-Main-3/INFO]: Preparing spawn area: 18%
|
||||||
|
[21:41:34] [Worker-Main-3/INFO]: Preparing spawn area: 20%
|
||||||
|
[21:41:35] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:35] [Worker-Main-1/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:36] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:36] [Worker-Main-2/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:37] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:37] [Worker-Main-1/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:38] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:38] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:39] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:39] [Worker-Main-2/INFO]: Preparing spawn area: 51%
|
||||||
|
[21:41:40] [Server thread/INFO]: Time elapsed: 17596 ms
|
||||||
|
[21:41:40] [Server thread/INFO]: Done (38.008s)! For help, type "help"
|
||||||
|
[21:41:40] [Server thread/INFO]: Starting remote control listener
|
||||||
|
[21:41:40] [Server thread/INFO]: Thread RCON Listener started
|
||||||
|
[21:41:40] [Server thread/INFO]: RCON running on 0.0.0.0:25575
|
||||||
|
[21:42:17] [User Authenticator #1/INFO]: UUID of player Sirherobrine23 is 0dc9df8f-9f5a-45d8-8848-9262a4357ae0
|
||||||
|
[21:42:20] [Server thread/INFO]: Sirherobrine23[/[0:0:0:0:0:0:0:1]:54662] logged in with entity id 41 at (37.5, 76.0, -57.5)
|
||||||
|
[21:42:20] [Server thread/INFO]: Sirherobrine23 joined the game
|
||||||
|
[21:43:42] [Server thread/WARN]: Sirherobrine23 moved too quickly! 9.663497831602484,3.176759275064242,0.8707508869438136
|
||||||
|
[21:43:42] [Server thread/WARN]: Can't keep up! Is the server overloaded? Running 4510ms or 90 ticks behind
|
||||||
|
[21:45:18] [Server thread/INFO]: Sirherobrine23 lost connection: Disconnected
|
||||||
|
[21:45:18] [Server thread/INFO]: Sirherobrine23 left the game
|
68
logs/java/1.7.10.txt
Normal file
68
logs/java/1.7.10.txt
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
[Log4jPatcher] [INFO] Transforming org/apache/logging/log4j/core/lookup/JndiLookup
|
||||||
|
[Log4jPatcher] [INFO] Transforming org/apache/logging/log4j/core/pattern/MessagePatternConverter
|
||||||
|
[Log4jPatcher] [WARN] Unable to find noLookups:Z field in org/apache/logging/log4j/core/pattern/MessagePatternConverter
|
||||||
|
Jan 19, 2025 6:36:38 PM io.netty.util.internal.PlatformDependent <clinit>
|
||||||
|
INFO: Your platform does not provide complete low-level API for accessing direct buffers reliably. Unless explicitly requested, heap buffer will always be preferred to avoid potential system unstability.
|
||||||
|
[18:36:38] [Server thread/INFO]: Starting minecraft server version 1.7.10
|
||||||
|
[18:36:38] [Server thread/INFO]: Loading properties
|
||||||
|
[18:36:38] [Server thread/INFO]: Default game type: SURVIVAL
|
||||||
|
[18:36:38] [Server thread/INFO]: Generating keypair
|
||||||
|
[18:36:38] [Server thread/INFO]: Starting Minecraft server on *:25565
|
||||||
|
[18:36:38] [Server thread/WARN]: Failed to load user banlist:
|
||||||
|
java.io.FileNotFoundException: banned-players.json (No such file or directory)
|
||||||
|
at java.base/java.io.FileInputStream.open0(Native Method) ~[?:?]
|
||||||
|
at java.base/java.io.FileInputStream.open(Unknown Source) ~[?:?]
|
||||||
|
at java.base/java.io.FileInputStream.<init>(Unknown Source) ~[?:?]
|
||||||
|
at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.7.10.jar:?]
|
||||||
|
at om.g(SourceFile:124) ~[minecraft_server.1.7.10.jar:?]
|
||||||
|
at ls.y(SourceFile:99) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at ls.<init>(SourceFile:25) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at lt.e(SourceFile:166) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at net.minecraft.server.MinecraftServer.run(SourceFile:339) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at lj.run(SourceFile:628) [minecraft_server.1.7.10.jar:?]
|
||||||
|
[18:36:38] [Server thread/WARN]: Failed to load ip banlist:
|
||||||
|
java.io.FileNotFoundException: banned-ips.json (No such file or directory)
|
||||||
|
at java.base/java.io.FileInputStream.open0(Native Method) ~[?:?]
|
||||||
|
at java.base/java.io.FileInputStream.open(Unknown Source) ~[?:?]
|
||||||
|
at java.base/java.io.FileInputStream.<init>(Unknown Source) ~[?:?]
|
||||||
|
at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.7.10.jar:?]
|
||||||
|
at om.g(SourceFile:124) ~[minecraft_server.1.7.10.jar:?]
|
||||||
|
at ls.x(SourceFile:91) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at ls.<init>(SourceFile:27) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at lt.e(SourceFile:166) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at net.minecraft.server.MinecraftServer.run(SourceFile:339) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at lj.run(SourceFile:628) [minecraft_server.1.7.10.jar:?]
|
||||||
|
[18:36:38] [Server thread/WARN]: Failed to load operators list:
|
||||||
|
java.io.FileNotFoundException: ops.json (No such file or directory)
|
||||||
|
at java.base/java.io.FileInputStream.open0(Native Method) ~[?:?]
|
||||||
|
at java.base/java.io.FileInputStream.open(Unknown Source) ~[?:?]
|
||||||
|
at java.base/java.io.FileInputStream.<init>(Unknown Source) ~[?:?]
|
||||||
|
at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.7.10.jar:?]
|
||||||
|
at om.g(SourceFile:124) ~[minecraft_server.1.7.10.jar:?]
|
||||||
|
at ls.z(SourceFile:107) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at ls.<init>(SourceFile:29) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at lt.e(SourceFile:166) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at net.minecraft.server.MinecraftServer.run(SourceFile:339) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at lj.run(SourceFile:628) [minecraft_server.1.7.10.jar:?]
|
||||||
|
[18:36:38] [Server thread/WARN]: Failed to load white-list:
|
||||||
|
java.io.FileNotFoundException: whitelist.json (No such file or directory)
|
||||||
|
at java.base/java.io.FileInputStream.open0(Native Method) ~[?:?]
|
||||||
|
at java.base/java.io.FileInputStream.open(Unknown Source) ~[?:?]
|
||||||
|
at java.base/java.io.FileInputStream.<init>(Unknown Source) ~[?:?]
|
||||||
|
at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.7.10.jar:?]
|
||||||
|
at om.g(SourceFile:124) ~[minecraft_server.1.7.10.jar:?]
|
||||||
|
at ls.B(SourceFile:123) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at ls.<init>(SourceFile:30) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at lt.e(SourceFile:166) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at net.minecraft.server.MinecraftServer.run(SourceFile:339) [minecraft_server.1.7.10.jar:?]
|
||||||
|
at lj.run(SourceFile:628) [minecraft_server.1.7.10.jar:?]
|
||||||
|
[18:36:38] [Server thread/INFO]: Preparing level "world"
|
||||||
|
[18:36:38] [Server thread/INFO]: Preparing start region for level 0
|
||||||
|
[18:36:39] [Server thread/INFO]: Preparing spawn area: 12%
|
||||||
|
[18:36:40] [Server thread/INFO]: Preparing spawn area: 28%
|
||||||
|
[18:36:41] [Server thread/INFO]: Preparing spawn area: 48%
|
||||||
|
[18:36:42] [Server thread/INFO]: Preparing spawn area: 69%
|
||||||
|
[18:36:43] [Server thread/INFO]: Preparing spawn area: 91%
|
||||||
|
[18:36:44] [Server thread/INFO]: Done (5.518s)! For help, type "help" or "?"
|
||||||
|
[18:36:44] [Server thread/INFO]: Starting remote control listener
|
||||||
|
[18:36:44] [RCON Listener #1/INFO]: RCON running on 0.0.0.0:25575
|
160
logs/java/java.go
Normal file
160
logs/java/java.go
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package java
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"net/netip"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/logs"
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/regex"
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/utils/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ = logs.RegisterParse[*JavaParse]("mojang/java") // Register platform
|
||||||
|
_ logs.Log = (*JavaParse)(nil)
|
||||||
|
_ logs.Player = (*JavaPlayer)(nil)
|
||||||
|
|
||||||
|
DoneMatch *regex.Regexp = regex.MustCompile(`Done \([0-9\.]+s\)! For help, type "help"( or "\?")?`)
|
||||||
|
)
|
||||||
|
|
||||||
|
type JavaPlayer struct {
|
||||||
|
Username string `json:"player"` // Player username
|
||||||
|
Actioned logs.Action `json:"action"` // Action type
|
||||||
|
Timed time.Time `json:"time"` // Action time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (player JavaPlayer) Name() string { return player.Username }
|
||||||
|
func (player JavaPlayer) Action() logs.Action { return player.Actioned }
|
||||||
|
func (player JavaPlayer) Time() time.Time { return player.Timed }
|
||||||
|
func (player JavaPlayer) XUID() int64 { return -1 }
|
||||||
|
|
||||||
|
type JavaParse struct {
|
||||||
|
ServerPlaform *logs.Server `json:"info"`
|
||||||
|
Players map[string][]logs.Player `json:"players"`
|
||||||
|
Errs []error `json:"errors"`
|
||||||
|
Warngs []error `json:"warnings"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (java JavaParse) Server() *logs.Server { return java.ServerPlaform }
|
||||||
|
func (java JavaParse) Errors() []error { return java.Errs }
|
||||||
|
func (java JavaParse) Warnings() []error { return java.Warngs }
|
||||||
|
func (java JavaParse) GetPlayer(name string) (player []logs.Player, ok bool) {
|
||||||
|
player, ok = java.Players[name]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (java *JavaParse) Parse(log io.Reader) error { return java.ParseTime(time.Now(), log) }
|
||||||
|
func (java *JavaParse) ParseTime(currentTime time.Time, log io.Reader) error {
|
||||||
|
java.ServerPlaform = &logs.Server{Platform: "mojang/java", Ports: []*logs.Port{}} // Init info
|
||||||
|
java.Errs, java.Warngs = []error{}, []error{}
|
||||||
|
java.Players = map[string][]logs.Player{}
|
||||||
|
|
||||||
|
valid, errorReference, scanner := false, error(nil), bufio.NewScanner(log)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
valid = true
|
||||||
|
if !(line[0] == 'U' || line[0] == 'S' || line[0] == '[') && errorReference != nil {
|
||||||
|
errorReference.(*logs.ErrorReference).Line = append(errorReference.(*logs.ErrorReference).Line, line)
|
||||||
|
continue
|
||||||
|
} else if !(line[0] == 'U' || line[0] == 'S' || line[0] == '[') {
|
||||||
|
valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if line[0] == 'U' || line[0] == 'S' {
|
||||||
|
continue // Ignore line
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixSplited := [3]string(strings.SplitAfterN(line, "]", 3))
|
||||||
|
prefixSplited[0] = strings.Replace(strings.Replace(strings.TrimSpace(prefixSplited[0][1:]), "[", "", 1), "]", "", 1)
|
||||||
|
prefixSplited[1] = strings.Replace(strings.Replace(strings.TrimSpace(prefixSplited[1][1:]), "[", "", 1), "]", "", 1)
|
||||||
|
prefixSplited[2] = strings.TrimSpace(prefixSplited[2][1:])
|
||||||
|
|
||||||
|
// Error log
|
||||||
|
if strings.HasSuffix(prefixSplited[1], "WARN") || strings.HasSuffix(prefixSplited[1], "ERROR") {
|
||||||
|
errorReference = &logs.ErrorReference{
|
||||||
|
LogLevel: 1,
|
||||||
|
FistLine: prefixSplited[2],
|
||||||
|
}
|
||||||
|
java.Warngs = append(java.Warngs, errorReference)
|
||||||
|
continue
|
||||||
|
} else if prefixSplited[0][0:4] == "Log4" { // log4j ignore
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
errorReference = nil
|
||||||
|
timeMoment, err := time.ParseInLocation(time.TimeOnly, prefixSplited[0], time.Local)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
currentTime = currentTime.Add(time.Hour*time.Duration(timeMoment.Hour()) + time.Minute*time.Duration(timeMoment.Minute()) + time.Second*time.Duration(timeMoment.Second()))
|
||||||
|
|
||||||
|
if DoneMatch.Match([]byte(prefixSplited[2])) {
|
||||||
|
java.ServerPlaform.Started = currentTime
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
contentExplode := slice.Slice[string](strings.Fields(prefixSplited[2]))
|
||||||
|
switch contentExplode.At(0) {
|
||||||
|
case "RCON":
|
||||||
|
if contentExplode.At(-2) == "on" {
|
||||||
|
addr, err := netip.ParseAddrPort(contentExplode.At(-1))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
java.ServerPlaform.Ports = append(java.ServerPlaform.Ports, &logs.Port{AddrPort: addr, From: "RCON"})
|
||||||
|
}
|
||||||
|
case "Starting":
|
||||||
|
switch contentExplode.At(-2) {
|
||||||
|
case "version":
|
||||||
|
version := contentExplode.At(-1)
|
||||||
|
java.ServerPlaform.Version = version
|
||||||
|
case "on":
|
||||||
|
Value := contentExplode.At(-1)
|
||||||
|
if Value[0] == '*' {
|
||||||
|
Value = Value[2:]
|
||||||
|
}
|
||||||
|
port, _ := strconv.ParseInt(Value, 10, 16)
|
||||||
|
java.ServerPlaform.Ports = append(java.ServerPlaform.Ports, &logs.Port{AddrPort: netip.AddrPortFrom(netip.IPv4Unspecified(), uint16(port)), From: "TCP"})
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
switch contentExplode.At(-1) {
|
||||||
|
case "game":
|
||||||
|
at3 := strings.ToLower(contentExplode.At(-3))
|
||||||
|
if slices.Contains([]string{"left", "joined"}, at3) {
|
||||||
|
playerName := prefixSplited[2][:strings.LastIndex(prefixSplited[2], contentExplode.At(-3))-1]
|
||||||
|
if _, ok := java.Players[playerName]; !ok {
|
||||||
|
java.Players[playerName] = []logs.Player{}
|
||||||
|
}
|
||||||
|
|
||||||
|
action := logs.Action(0)
|
||||||
|
switch at3 {
|
||||||
|
case "joined":
|
||||||
|
action = logs.Connect
|
||||||
|
case "left":
|
||||||
|
action = logs.Disconnect
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append to struct
|
||||||
|
java.Players[playerName] = append(java.Players[playerName], JavaPlayer{
|
||||||
|
Username: playerName,
|
||||||
|
Actioned: action,
|
||||||
|
Timed: currentTime,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
} else if valid { // return nil if platform is valid
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return logs.ErrSkipPlatform
|
||||||
|
}
|
35
logs/java/java_test.go
Normal file
35
logs/java/java_test.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package java
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testPrintLog(t *testing.T, textPrint string, log *JavaParse) {
|
||||||
|
d, _ := json.MarshalIndent(log, "", " ")
|
||||||
|
t.Logf(textPrint, string(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDetectAndParseJava(t *testing.T) {
|
||||||
|
parsedLog, err := &JavaParse{}, error(nil)
|
||||||
|
if err = parsedLog.Parse(strings.NewReader(StaticLogFileJava1)); err != nil {
|
||||||
|
t.Errorf("Cannot parse java log 1: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
testPrintLog(t, "Parsed log java Static 1:\n%s", parsedLog)
|
||||||
|
|
||||||
|
if err = parsedLog.Parse(strings.NewReader(StaticLogFileJava2)); err != nil {
|
||||||
|
t.Errorf("Cannot parse java log 2: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
testPrintLog(t, "Parsed log java Static 2:\n%s", parsedLog)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed 1.21.4.txt
|
||||||
|
StaticLogFileJava1 string
|
||||||
|
//go:embed 1.7.10.txt
|
||||||
|
StaticLogFileJava2 string
|
||||||
|
)
|
162
logs/logs.go
Normal file
162
logs/logs.go
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/netip"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrPlayerNotExist error = errors.New("player not exists") // Player not exists or not never connected in server session
|
||||||
|
ErrSkipPlatform error = errors.New("skip platform parse") // Skip current platform parse and continue to next if avaible
|
||||||
|
ErrCannotDetectPlatform error = errors.New("cannot detect log platform") // Platform log not detected or not loaded
|
||||||
|
|
||||||
|
reflectParse = map[string]reflect.Type{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register parse to log Dectect platform
|
||||||
|
func RegisterParse[Parse Log](name string) bool {
|
||||||
|
if _, ok := reflectParse[name]; !ok {
|
||||||
|
reflectParse[name] = reflect.TypeFor[Parse]()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type Action int // Player actions
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ Action = iota
|
||||||
|
Disconnect // Player disconnected from server
|
||||||
|
Connect // Player connected to server
|
||||||
|
Spawned // Player connected to server and spawned in world server
|
||||||
|
Banned // Player is banned from server by operator
|
||||||
|
|
||||||
|
PlayerActionsValid = Disconnect | Connect | Spawned | Banned // Check if actions is valid
|
||||||
|
)
|
||||||
|
|
||||||
|
func (act Action) String() string {
|
||||||
|
switch act {
|
||||||
|
case Disconnect:
|
||||||
|
return "disconnect"
|
||||||
|
case Connect:
|
||||||
|
return "connect"
|
||||||
|
case Spawned:
|
||||||
|
return "spawned"
|
||||||
|
case Banned:
|
||||||
|
return "banned"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (act Action) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(act.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (act *Action) UnmarshalText(data []byte) error {
|
||||||
|
switch string(data) {
|
||||||
|
case "disconnect":
|
||||||
|
*act = Disconnect
|
||||||
|
case "connect":
|
||||||
|
*act = Connect
|
||||||
|
case "spawned":
|
||||||
|
*act = Spawned
|
||||||
|
case "banned":
|
||||||
|
*act = Banned
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown action: %s", data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Port struct {
|
||||||
|
AddrPort netip.AddrPort `json:"addr"` // Port and ip address
|
||||||
|
From string `json:"from"` // Server listened protocol, TCP/UDP/Unix...
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ error = &ErrorReference{}
|
||||||
|
|
||||||
|
type ErrorReference struct {
|
||||||
|
LogLevel int
|
||||||
|
FistLine string
|
||||||
|
Line []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *ErrorReference) Error() string {
|
||||||
|
errLevel := "error"
|
||||||
|
if err.LogLevel == 1 {
|
||||||
|
errLevel = "warning"
|
||||||
|
} else if err.LogLevel >= 2 {
|
||||||
|
errLevel = "fatal"
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(fmt.Sprintf("%s: %s", errLevel, err.FistLine))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *ErrorReference) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *ErrorReference) Unwrap() []error {
|
||||||
|
return []error{
|
||||||
|
err,
|
||||||
|
errors.New(strings.Join(err.Line, "\n")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server info
|
||||||
|
type Server struct {
|
||||||
|
Version string `json:"version"` // Server version if avaible
|
||||||
|
Started time.Time `json:"started"` // Time server started or avaible to connect
|
||||||
|
Platform string `json:"platform"` // Server platform, example: bedrock, java, pocketmine...
|
||||||
|
Ports []*Port `json:"ports"` // Server ports listened
|
||||||
|
}
|
||||||
|
|
||||||
|
type Player interface {
|
||||||
|
Name() string // Player username
|
||||||
|
Action() Action // Player action
|
||||||
|
Time() time.Time // Action time
|
||||||
|
XUID() int64 // Xbox XUID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements log parse and return based log info
|
||||||
|
type Log interface {
|
||||||
|
ParseTime(time.Time, io.Reader) error // Parse log with server date
|
||||||
|
Parse(io.Reader) error // Parse log with current time
|
||||||
|
Server() *Server // Server info
|
||||||
|
GetPlayer(string) ([]Player, bool) // Get player info
|
||||||
|
Errors() []error // Get log errors
|
||||||
|
Warnings() []error // Get log warnings
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse log
|
||||||
|
func Parse(log io.ReadSeeker) (Log, error) {
|
||||||
|
for _, typeOf := range reflectParse {
|
||||||
|
platformLog := reflect.New(typeOf.Elem()).Interface().(Log)
|
||||||
|
if err := platformLog.Parse(log); err != nil {
|
||||||
|
if err == ErrSkipPlatform {
|
||||||
|
if _, err = log.Seek(0, io.SeekStart); err == nil {
|
||||||
|
continue // Skip
|
||||||
|
}
|
||||||
|
err = fmt.Errorf("cannot seek log file: %s", err)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return platformLog, nil
|
||||||
|
}
|
||||||
|
return nil, ErrCannotDetectPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse string log
|
||||||
|
func ParseString(log string) (Log, error) {
|
||||||
|
return Parse(strings.NewReader(log))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse buffer log
|
||||||
|
func ParseBuffer(log []byte) (Log, error) {
|
||||||
|
return Parse(bytes.NewReader(log))
|
||||||
|
}
|
35
logs/logs_test.go
Normal file
35
logs/logs_test.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package logs_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/logs"
|
||||||
|
_ "sirherobrine23.com.br/go-bds/go-bds/logs/bedrock"
|
||||||
|
_ "sirherobrine23.com.br/go-bds/go-bds/logs/java"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed */1.*.txt
|
||||||
|
var LogFiles embed.FS
|
||||||
|
|
||||||
|
func TestLogs(t *testing.T) {
|
||||||
|
err := fs.WalkDir(LogFiles, ".", func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
file, _ := LogFiles.Open(path)
|
||||||
|
if _, err = logs.Parse(file.(io.ReadSeeker)); err != nil {
|
||||||
|
return fmt.Errorf("cannot parse %s: %s", path, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
100
logs/mclog/fs.go
Normal file
100
logs/mclog/fs.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package mclog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/overlayfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ FileSystem = Local("")
|
||||||
|
_ FileSystem = &Mergefs{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type File interface {
|
||||||
|
fs.File
|
||||||
|
io.Seeker
|
||||||
|
io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileSystem interface {
|
||||||
|
fs.FS
|
||||||
|
Create(string) (File, error)
|
||||||
|
Mkdir(string, fs.FileMode) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func MkdirAll(fss FileSystem, dir string, perm fs.FileMode) error {
|
||||||
|
paths := strings.Split(filepath.ToSlash(dir), "/")
|
||||||
|
for pathIndex := range paths {
|
||||||
|
if err := fss.Mkdir(path.Join(paths[:pathIndex]...), perm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateID(fss FileSystem, dir string) (string, File, error) {
|
||||||
|
dir = path.Clean(filepath.ToSlash(dir))
|
||||||
|
if _, err := fs.Stat(fss, dir); err != nil {
|
||||||
|
if err := MkdirAll(fss, dir, 0755); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
id := make([]byte, 16)
|
||||||
|
for attemps := 8; attemps > 0; attemps-- {
|
||||||
|
if _, err := rand.Read(id); err != nil {
|
||||||
|
return "", nil, &fs.PathError{Op: "create", Path: dir, Err: err}
|
||||||
|
}
|
||||||
|
id[6] = (id[6] & 0x0f) | 0x40
|
||||||
|
id[8] = (id[8] & 0x3f) | 0x80
|
||||||
|
name := fmt.Sprintf("%x", id)
|
||||||
|
if _, err := fs.Stat(fss, path.Join(dir, name)); err == nil {
|
||||||
|
continue // Skip exists
|
||||||
|
} else if file, err := fss.Create(path.Join(dir, name)); err == nil {
|
||||||
|
return name, file, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil, &fs.PathError{Op: "create", Path: dir, Err: fmt.Errorf("cannot make file id")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maneger log files in Local disk
|
||||||
|
type Local string
|
||||||
|
|
||||||
|
func (local Local) Open(name string) (fs.File, error) { return os.OpenInRoot(string(local), name) }
|
||||||
|
func (local Local) Mkdir(name string, perm fs.FileMode) error {
|
||||||
|
r, err := os.OpenRoot(string(local))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
return r.Mkdir(name, perm.Perm())
|
||||||
|
}
|
||||||
|
func (local Local) Create(name string) (File, error) {
|
||||||
|
r, err := os.OpenRoot(string(local))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
return r.Create(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mergefs overlayfs.FsMergeFs
|
||||||
|
|
||||||
|
func (fss Mergefs) Open(name string) (fs.File, error) { return overlayfs.FsMergeFs(fss).Open(name) }
|
||||||
|
func (fss Mergefs) Mkdir(name string, perm fs.FileMode) error {
|
||||||
|
return overlayfs.FsMergeFs(fss).MergedFS.Mkdir(filepath.Join(fss.Subdir, filepath.Clean(name)), perm.Perm())
|
||||||
|
}
|
||||||
|
func (fss Mergefs) Create(name string) (File, error) {
|
||||||
|
if fss.MergedFS == nil {
|
||||||
|
return nil, fs.ErrInvalid
|
||||||
|
}
|
||||||
|
return fss.MergedFS.Create(filepath.Join(fss.Subdir, filepath.Clean(name)))
|
||||||
|
}
|
@ -2,7 +2,10 @@ package mclog
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/logs"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -23,6 +26,12 @@ const (
|
|||||||
LogWarn LogLevel = "warning"
|
LogWarn LogLevel = "warning"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Limits struct {
|
||||||
|
StorageTime time.Duration `json:"storageTime"` // The duration in seconds that a log is stored for after the last view.
|
||||||
|
MaxLength int64 `json:"maxLength"` // Maximum file length in bytes. Logs over this limit will be truncated to this length.
|
||||||
|
MaxLines int64 `json:"maxLines"` // Maximum number of lines. Additional lines will be removed.
|
||||||
|
}
|
||||||
|
|
||||||
// Stands log levels
|
// Stands log levels
|
||||||
type LogLevel string
|
type LogLevel string
|
||||||
|
|
||||||
@ -32,12 +41,6 @@ type MclogResponseStatus struct {
|
|||||||
Id string `json:"id,omitempty"` // If post log file return id if processed
|
Id string `json:"id,omitempty"` // If post log file return id if processed
|
||||||
}
|
}
|
||||||
|
|
||||||
type Limits struct {
|
|
||||||
StorageTime time.Duration `json:"storageTime"` // The duration in seconds that a log is stored for after the last view.
|
|
||||||
MaxLength int64 `json:"maxLength"` // Maximum file length in bytes. Logs over this limit will be truncated to this length.
|
|
||||||
MaxLines int64 `json:"maxLines"` // Maximum number of lines. Additional lines will be removed.
|
|
||||||
}
|
|
||||||
|
|
||||||
type EntryLine struct {
|
type EntryLine struct {
|
||||||
Numbers int `json:"number"`
|
Numbers int `json:"number"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
@ -68,3 +71,41 @@ type Insights struct {
|
|||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Analysis map[LogLevel][]*InsightsAnalysis `json:"analysis"`
|
Analysis map[LogLevel][]*InsightsAnalysis `json:"analysis"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ConvertLogs(id string, log logs.Log) Insights {
|
||||||
|
var insight Insights
|
||||||
|
insight.Type = "server"
|
||||||
|
insight.ID = id
|
||||||
|
|
||||||
|
serverInfo := log.Server()
|
||||||
|
insight.Version = serverInfo.Version
|
||||||
|
insight.Name = serverInfo.Platform
|
||||||
|
insight.Title = fmt.Sprintf("%s - %s", serverInfo.Platform, serverInfo.Version)
|
||||||
|
|
||||||
|
insight.Analysis = map[LogLevel][]*InsightsAnalysis{}
|
||||||
|
insight.Analysis[LogInfo] = append(insight.Analysis[LogInfo], &InsightsAnalysis{
|
||||||
|
Label: "Started time",
|
||||||
|
Value: serverInfo.Started.Format(time.RFC3339),
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, port := range serverInfo.Ports {
|
||||||
|
insight.Analysis[LogInfo] = append(insight.Analysis[LogInfo], &InsightsAnalysis{
|
||||||
|
Label: "Port listen",
|
||||||
|
Message: port.From,
|
||||||
|
Value: port.AddrPort.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, err := range log.Errors() {
|
||||||
|
insight.Analysis[LogProblem] = append(insight.Analysis[LogProblem], &InsightsAnalysis{
|
||||||
|
Value: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, err := range log.Warnings() {
|
||||||
|
insight.Analysis[LogWarn] = append(insight.Analysis[LogWarn], &InsightsAnalysis{
|
||||||
|
Value: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return insight
|
||||||
|
}
|
365
logs/mclog/server.go
Normal file
365
logs/mclog/server.go
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
package mclog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"maps"
|
||||||
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/logs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeJson(w http.ResponseWriter, code int, v any) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(code)
|
||||||
|
jsenc := json.NewEncoder(w)
|
||||||
|
jsenc.SetIndent("", " ")
|
||||||
|
jsenc.Encode(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(limits Limits, fss FileSystem) http.Handler {
|
||||||
|
fss.Mkdir("v2", 0755) // Ignore error's
|
||||||
|
mux, v1, v2 := http.NewServeMux(), http.NewServeMux(), http.NewServeMux()
|
||||||
|
|
||||||
|
// mclogs limits
|
||||||
|
v1Limits, _ := json.MarshalIndent(map[string]any{
|
||||||
|
"storageTime": int(limits.StorageTime.Seconds()),
|
||||||
|
"maxLength": limits.MaxLength,
|
||||||
|
"maxLines": limits.MaxLines,
|
||||||
|
}, "", " ")
|
||||||
|
|
||||||
|
// V1 from mclogs
|
||||||
|
v1.HandleFunc("GET /limits", func(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write(v1Limits)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Storage log
|
||||||
|
v1.HandleFunc("POST /log", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if slices.Contains(r.Header.Values("Content-Type"), "application/x-www-form-urlencoded") {
|
||||||
|
r.ParseForm()
|
||||||
|
}
|
||||||
|
if !(r.Form.Has("content") || r.Form.Get("content") == "") {
|
||||||
|
writeJson(w, 400, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": "Required POST argument 'content' is empty.",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if limits.MaxLines > 0 || limits.MaxLength > 0 {
|
||||||
|
lines := strings.Split(r.Form.Get("content"), "\n")
|
||||||
|
content := strings.Join(lines[:min(len(lines)-1, int(limits.MaxLines))], "\n")
|
||||||
|
if limits.MaxLength > 0 {
|
||||||
|
content = content[:min(len(content), int(limits.MaxLength))]
|
||||||
|
}
|
||||||
|
r.Form.Set("content", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := logs.ParseString(r.Form.Get("content")); err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id, file, err := CreateID(fss, ".")
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 500, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": fmt.Errorf("canont create file and id: %s", err).Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if _, err = io.WriteString(file, r.Form.Get("content")); err != nil {
|
||||||
|
writeJson(w, 500, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": fmt.Errorf("canont write log to file: %s", err).Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJson(w, 200, map[string]any{
|
||||||
|
"success": true,
|
||||||
|
"id": id,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get log
|
||||||
|
v1.HandleFunc("GET /raw/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
file, err := fss.Open(r.PathValue("id"))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
writeJson(w, 404, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": "Log not found.",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
writeJson(w, 400, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
w.WriteHeader(200)
|
||||||
|
io.Copy(w, file)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get log insights
|
||||||
|
v1.HandleFunc("GET /insights/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
file, err := fss.Open(r.PathValue("id"))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
writeJson(w, 404, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": "Log not found.",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
writeJson(w, 400, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
buff, err := io.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 500, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log, err := logs.ParseBuffer(buff)
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 500, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJson(w, 500, ConvertLogs(r.PathValue("id"), log))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Analyse a log without saving it
|
||||||
|
v1.HandleFunc("POST /analyse", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if slices.Contains(r.Header.Values("Content-Type"), "application/x-www-form-urlencoded") {
|
||||||
|
r.ParseForm()
|
||||||
|
}
|
||||||
|
if !(r.Form.Has("content") || r.Form.Get("content") == "") {
|
||||||
|
writeJson(w, 400, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": "Required POST argument 'content' is empty.",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if limits.MaxLines > 0 || limits.MaxLength > 0 {
|
||||||
|
lines := strings.Split(r.Form.Get("content"), "\n")
|
||||||
|
content := strings.Join(lines[:min(len(lines)-1, int(limits.MaxLines))], "\n")
|
||||||
|
if limits.MaxLength > 0 {
|
||||||
|
content = content[:min(len(content), int(limits.MaxLength))]
|
||||||
|
}
|
||||||
|
r.Form.Set("content", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
log, err := logs.ParseString(r.Form.Get("content"))
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{
|
||||||
|
"success": false,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJson(w, 200, ConvertLogs("", log))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Server v2
|
||||||
|
v2Info, _ := json.MarshalIndent(map[string]any{"runtime": runtime.Version(), "limits": limits}, "", " ")
|
||||||
|
v2.HandleFunc("GET /{$}", func(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write(v2Info)
|
||||||
|
w.Write(nil)
|
||||||
|
})
|
||||||
|
|
||||||
|
v2.HandleFunc("POST /{$}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
logString, parsedLogs := []string{}, map[string]logs.Log{}
|
||||||
|
if slices.Contains(r.Header.Values("Content-Type"), "application/octet-stream") {
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("cannot read json body: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logString = append(logString, string(body))
|
||||||
|
} else if slices.Contains(r.Header.Values("Content-Type"), "multipart/form-data") {
|
||||||
|
if err := r.ParseMultipartForm(10 << 20); err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("cannot parse form: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, content := range r.MultipartForm.Value {
|
||||||
|
logString = append(logString, content...)
|
||||||
|
}
|
||||||
|
for _, content := range r.MultipartForm.File {
|
||||||
|
for _, file := range content {
|
||||||
|
info, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("cannot read json body: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer info.Close()
|
||||||
|
body, err := io.ReadAll(info)
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("cannot read json body: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logString = append(logString, string(body))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if slices.Contains(r.Header.Values("Content-Type"), "application/x-www-form-urlencoded") {
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("cannot parse form: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, content := range r.Form {
|
||||||
|
logString = append(logString, content...)
|
||||||
|
}
|
||||||
|
} else if slices.Contains(r.Header.Values("Content-Type"), "application/json") {
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("cannot read json body: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var data any
|
||||||
|
if err = json.Unmarshal(body, &data); err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("cannot parse json: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := data.(type) {
|
||||||
|
case []string:
|
||||||
|
logString = v
|
||||||
|
case map[string]string:
|
||||||
|
logString = slices.Collect(maps.Values(v))
|
||||||
|
default:
|
||||||
|
writeJson(w, 400, map[string]any{"error": "invalid data type", "tips": "[]string, map[string]string"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeJson(w, 400, map[string]any{"error": "require Content-Type in header"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := error(nil)
|
||||||
|
for _, log := range logString {
|
||||||
|
log = strings.TrimSpace(log)
|
||||||
|
sum := sha256.Sum256([]byte(log))
|
||||||
|
if parsedLogs[hex.EncodeToString(sum[:])], err = logs.ParseString(log); err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("cannot parse json: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeJson(w, 200, parsedLogs)
|
||||||
|
})
|
||||||
|
|
||||||
|
v2.HandleFunc("POST /raw", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !slices.Contains(r.Header.Values("Content-Type"), "application/octet-stream") {
|
||||||
|
writeJson(w, 400, map[string]any{"error": "require application/octet-stream on Content-Type header"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("cannot get full body: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body = []byte(strings.TrimSpace(string(body)))
|
||||||
|
if _, err = logs.ParseBuffer(body); err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("invalid log: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSum := sha256.Sum256(body)
|
||||||
|
fileID := hex.EncodeToString(fileSum[:])
|
||||||
|
remoteFile, err := fss.Open(path.Join("v2", fileID))
|
||||||
|
if remoteFile != nil {
|
||||||
|
remoteFile.Close() // Close file
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("fs error: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
create, err := fss.Create(path.Join("v2", fileID))
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("fs error: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
create.Write(body)
|
||||||
|
create.Close()
|
||||||
|
}
|
||||||
|
writeJson(w, 200, map[string]any{"id": fileID})
|
||||||
|
})
|
||||||
|
|
||||||
|
v2.HandleFunc("GET /raw/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
file, err := fss.Open(path.Join("v2", r.PathValue("id")))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
writeJson(w, 404, map[string]any{"error": "file not exists"})
|
||||||
|
} else {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("fs error: %s", err).Error()})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
io.Copy(w, file)
|
||||||
|
})
|
||||||
|
v2.HandleFunc("GET /insight/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
file, err := fss.Open(path.Join("v2", r.PathValue("id")))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
writeJson(w, 404, map[string]any{"error": "file not exists"})
|
||||||
|
} else {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("fs error: %s", err).Error()})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
body, err := io.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("read: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log, err := logs.ParseBuffer(body)
|
||||||
|
if err != nil {
|
||||||
|
writeJson(w, 400, map[string]any{"error": fmt.Errorf("logs parse: %s", err).Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJson(w, 200, log)
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.Handle("/1/", http.StripPrefix("/1", v1))
|
||||||
|
mux.Handle("/v1/", http.StripPrefix("/v1", v1))
|
||||||
|
mux.Handle("/v2/", http.StripPrefix("/v2", v2))
|
||||||
|
return mux
|
||||||
|
}
|
38
logs/mclog/server/main.go
Normal file
38
logs/mclog/server/main.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
_ "sirherobrine23.com.br/go-bds/go-bds/logs/bedrock"
|
||||||
|
_ "sirherobrine23.com.br/go-bds/go-bds/logs/java"
|
||||||
|
"sirherobrine23.com.br/go-bds/go-bds/logs/mclog"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
PortPoint = flag.Int("port", 0, "Port to listen http server")
|
||||||
|
Rootdir = flag.String("root", filepath.Join(os.TempDir(), "bdsmclogs"), "Folder to save log files")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
rootDir, port := *Rootdir, uint16(*PortPoint)
|
||||||
|
os.MkdirAll(rootDir, 0755)
|
||||||
|
|
||||||
|
limits := mclog.Limits{}
|
||||||
|
handler := mclog.NewHandler(limits, mclog.Local(rootDir))
|
||||||
|
|
||||||
|
listen, err := net.ListenTCP("tcp", net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), port)))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "cannot listen http server: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "HTTP server listening on %s\n", listen.Addr().String())
|
||||||
|
http.Serve(listen, handler)
|
||||||
|
}
|
@ -1,80 +0,0 @@
|
|||||||
package mclog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrCannotParse error = errors.New("cannot detect server")
|
|
||||||
ErrSkipParse error = errors.New("skip parse log")
|
|
||||||
)
|
|
||||||
|
|
||||||
type ServerParse interface {
|
|
||||||
Detect(log io.ReadSeeker) error // Check if log is compatible and parse
|
|
||||||
Insight() *Insights // Return mclog Insights
|
|
||||||
}
|
|
||||||
|
|
||||||
type PlatformParse interface {
|
|
||||||
String() string // Platform name, ex: 'mojang:bedrock', 'mojang:java', 'spigot', 'paper', 'pocketmine'
|
|
||||||
New() (ServerParse, error) // Return new server parse
|
|
||||||
}
|
|
||||||
|
|
||||||
var logParses = []PlatformParse{}
|
|
||||||
|
|
||||||
func ParsesRegitred() []string {
|
|
||||||
names := []string{}
|
|
||||||
for _, n := range logParses {
|
|
||||||
names = append(names, n.String())
|
|
||||||
}
|
|
||||||
return names
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new server log process
|
|
||||||
func RegisterNewParse(loger PlatformParse) bool {
|
|
||||||
if loger == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, value := range logParses {
|
|
||||||
if value == loger || value.String() == loger.String() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logParses = append(logParses, loger)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse log
|
|
||||||
func ParseLog(input io.Reader) (*Insights, error) {
|
|
||||||
if st, ok := input.(io.ReadSeeker); !ok {
|
|
||||||
buffer, err := io.ReadAll(st)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
input = bytes.NewReader(buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
reader := input.(io.ReadSeeker)
|
|
||||||
for _, server := range logParses {
|
|
||||||
parse, err := server.New()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = parse.Detect(reader)
|
|
||||||
switch err {
|
|
||||||
case ErrSkipParse:
|
|
||||||
// Reset stream
|
|
||||||
if _, err = reader.Seek(0, io.SeekStart); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
continue // Skip parse
|
|
||||||
case nil:
|
|
||||||
return parse.Insight(), nil
|
|
||||||
default:
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, ErrCannotParse
|
|
||||||
}
|
|
@ -1,344 +0,0 @@
|
|||||||
package mclog_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
. "sirherobrine23.com.br/go-bds/go-bds/mclog"
|
|
||||||
_ "sirherobrine23.com.br/go-bds/go-bds/bedrock"
|
|
||||||
_ "sirherobrine23.com.br/go-bds/go-bds/java"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLog(t *testing.T) {
|
|
||||||
var Insights []*Insights
|
|
||||||
|
|
||||||
for _, logString := range Loger {
|
|
||||||
insight, err := ParseLog(strings.NewReader(logString))
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%s:\n%s", err, logString)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Insights = append(Insights, insight)
|
|
||||||
}
|
|
||||||
|
|
||||||
d, _ := json.MarshalIndent(Insights, "", " ")
|
|
||||||
println(string(d))
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
Loger = []string{
|
|
||||||
`NO LOG FILE! - setting up server logging...
|
|
||||||
[2022-11-16 19:34:11:606 INFO] Starting Server
|
|
||||||
[2022-11-16 19:34:11:606 INFO] Version 1.19.41.01
|
|
||||||
[2022-11-16 19:34:11:606 INFO] Session ID d914c8d5-2ad1-46fd-b213-e76ed4e6caca
|
|
||||||
[2022-11-16 19:34:11:606 INFO] Level Name: Sirherobrine23
|
|
||||||
[2022-11-16 19:34:11:609 INFO] Game mode: 0 Survival
|
|
||||||
[2022-11-16 19:34:11:609 INFO] Difficulty: 2 NORMAL
|
|
||||||
[2022-11-16 19:34:11:729 INFO] opening worlds/Sirherobrine23/db
|
|
||||||
[2022-11-16 19:34:12:336 INFO] IPv4 supported, port: 19132
|
|
||||||
[2022-11-16 19:34:12:337 INFO] IPv6 supported, port: 19133
|
|
||||||
[2022-11-16 19:34:13:002 INFO] Server started.
|
|
||||||
[2022-11-16 19:34:13:008 INFO] Please note that LAN discovery will not function for this server.
|
|
||||||
[2022-11-16 19:34:13:008 INFO] Server IP must be specified in Servers tab in game.
|
|
||||||
[2022-11-16 19:34:13:052 INFO] ================ TELEMETRY MESSAGE ===================
|
|
||||||
[2022-11-16 19:34:13:052 INFO] Server Telemetry is currently not enabled.
|
|
||||||
[2022-11-16 19:34:13:052 INFO] Enabling this telemetry helps us improve the game.
|
|
||||||
[2022-11-16 19:34:13:052 INFO]
|
|
||||||
[2022-11-16 19:34:13:052 INFO] To enable this feature, add the line 'emit-server-telemetry=true'
|
|
||||||
[2022-11-16 19:34:13:052 INFO] to the server.properties file in the handheld/src-server directory
|
|
||||||
[2022-11-16 19:34:13:052 INFO] ======================================================
|
|
||||||
[2022-11-16 19:55:44:503 INFO] Player connected: Sirherobrine, xuid: 2535413418839840
|
|
||||||
[2022-11-16 19:55:49:400 INFO] Player Spawned: Sirherobrine xuid: 2535413418839840
|
|
||||||
[2022-11-16 19:56:59:378 INFO] Player disconnected: Sirherobrine, xuid: 2535413418839840
|
|
||||||
[2022-11-16 20:01:48:937 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-16 20:07:48:959 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-19 19:23:22:600 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-19 19:29:22:601 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-19 19:35:22:602 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-19 19:41:23:746 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-19 19:47:23:746 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-19 19:53:23:747 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-19 19:59:23:748 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-19 20:05:24:904 INFO] Running AutoCompaction...
|
|
||||||
[2022-11-19 20:07:15:776 INFO] Player connected: Sirherobrine, xuid: 2535413418839840
|
|
||||||
[2022-11-19 20:07:30:911 INFO] Player Spawned: Sirherobrine xuid: 2535413418839840`,
|
|
||||||
`NO LOG FILE! - setting up server logging...
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Starting Server
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Version 1.6.1.0
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Level Name: Bedrock level
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:13 ERROR] Error opening whitelist file: whitelist.json
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:13 ERROR] Error opening ops file: ops.json
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Game mode: 0 Survival
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:13 INFO] Difficulty: 1 EASY
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:13 INFO] IPv4 supported, port: 19132
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:13 INFO] IPv6 supported, port: 19133
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:14 INFO] Listening on IPv6 port: 19133
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:14 INFO] Listening on IPv4 port: 19132
|
|
||||||
NO LOG FILE! - [2025-01-19 23:35:18 INFO] Player connected: 2535413418839840
|
|
||||||
NO LOG FILE! - [2025-01-19 23:38:54 INFO] Player disconnected: 2535413418839840
|
|
||||||
NO LOG FILE! - [2025-01-19 23:40:13 INFO] Player connected:
|
|
||||||
NO LOG FILE! - [2025-01-19 23:40:54 INFO] Player disconnected:
|
|
||||||
`,
|
|
||||||
`Unpacking 1.21.4/server-1.21.4.jar (versions:1.21.4) to versions/1.21.4/server-1.21.4.jar
|
|
||||||
Unpacking com/fasterxml/jackson/core/jackson-annotations/2.13.4/jackson-annotations-2.13.4.jar (libraries:com.fasterxml.jackson.core:jackson-annotations:2.13.4) to libraries/com/fasterxml/jackson/core/jackson-annotations/2.13.4/jackson-annotations-2.13.4.jar
|
|
||||||
Unpacking com/fasterxml/jackson/core/jackson-core/2.13.4/jackson-core-2.13.4.jar (libraries:com.fasterxml.jackson.core:jackson-core:2.13.4) to libraries/com/fasterxml/jackson/core/jackson-core/2.13.4/jackson-core-2.13.4.jar
|
|
||||||
Unpacking com/fasterxml/jackson/core/jackson-databind/**.**.**.**/jackson-databind-2.13.4.2.jar (libraries:com.fasterxml.jackson.core:jackson-databind:**.**.**.**) to libraries/com/fasterxml/jackson/core/jackson-databind/**.**.**.**/jackson-databind-2.13.4.2.jar
|
|
||||||
Unpacking com/github/oshi/oshi-core/6.6.5/oshi-core-6.6.5.jar (libraries:com.github.oshi:oshi-core:6.6.5) to libraries/com/github/oshi/oshi-core/6.6.5/oshi-core-6.6.5.jar
|
|
||||||
Unpacking com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar (libraries:com.github.stephenc.jcip:jcip-annotations:1.0-1) to libraries/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar
|
|
||||||
Unpacking com/google/code/gson/gson/2.11.0/gson-2.11.0.jar (libraries:com.google.code.gson:gson:2.11.0) to libraries/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar
|
|
||||||
Unpacking com/google/guava/failureaccess/1.0.2/failureaccess-1.0.2.jar (libraries:com.google.guava:failureaccess:1.0.2) to libraries/com/google/guava/failureaccess/1.0.2/failureaccess-1.0.2.jar
|
|
||||||
Unpacking com/google/guava/guava/33.3.1-jre/guava-33.3.1-jre.jar (libraries:com.google.guava:guava:33.3.1-jre) to libraries/com/google/guava/guava/33.3.1-jre/guava-33.3.1-jre.jar
|
|
||||||
Unpacking com/microsoft/azure/msal4j/1.17.2/msal4j-1.17.2.jar (libraries:com.microsoft.azure:msal4j:1.17.2) to libraries/com/microsoft/azure/msal4j/1.17.2/msal4j-1.17.2.jar
|
|
||||||
Unpacking com/mojang/authlib/6.0.57/authlib-6.0.57.jar (libraries:com.mojang:authlib:6.0.57) to libraries/com/mojang/authlib/6.0.57/authlib-6.0.57.jar
|
|
||||||
Unpacking com/mojang/brigadier/1.3.10/brigadier-1.3.10.jar (libraries:com.mojang:brigadier:1.3.10) to libraries/com/mojang/brigadier/1.3.10/brigadier-1.3.10.jar
|
|
||||||
Unpacking com/mojang/datafixerupper/8.0.16/datafixerupper-8.0.16.jar (libraries:com.mojang:datafixerupper:8.0.16) to libraries/com/mojang/datafixerupper/8.0.16/datafixerupper-8.0.16.jar
|
|
||||||
Unpacking com/mojang/jtracy/1.0.29/jtracy-1.0.29.jar (libraries:com.mojang:jtracy:1.0.29) to libraries/com/mojang/jtracy/1.0.29/jtracy-1.0.29.jar
|
|
||||||
Unpacking com/mojang/logging/1.5.10/logging-1.5.10.jar (libraries:com.mojang:logging:1.5.10) to libraries/com/mojang/logging/1.5.10/logging-1.5.10.jar
|
|
||||||
Unpacking com/nimbusds/content-type/2.3/content-type-2.3.jar (libraries:com.nimbusds:content-type:2.3) to libraries/com/nimbusds/content-type/2.3/content-type-2.3.jar
|
|
||||||
Unpacking com/nimbusds/lang-tag/1.7/lang-tag-1.7.jar (libraries:com.nimbusds:lang-tag:1.7) to libraries/com/nimbusds/lang-tag/1.7/lang-tag-1.7.jar
|
|
||||||
Unpacking com/nimbusds/nimbus-jose-jwt/9.40/nimbus-jose-jwt-9.40.jar (libraries:com.nimbusds:nimbus-jose-jwt:9.40) to libraries/com/nimbusds/nimbus-jose-jwt/9.40/nimbus-jose-jwt-9.40.jar
|
|
||||||
Unpacking com/nimbusds/oauth2-oidc-sdk/11.18/oauth2-oidc-sdk-11.18.jar (libraries:com.nimbusds:oauth2-oidc-sdk:11.18) to libraries/com/nimbusds/oauth2-oidc-sdk/11.18/oauth2-oidc-sdk-11.18.jar
|
|
||||||
Unpacking commons-io/commons-io/2.17.0/commons-io-2.17.0.jar (libraries:commons-io:commons-io:2.17.0) to libraries/commons-io/commons-io/2.17.0/commons-io-2.17.0.jar
|
|
||||||
Unpacking io/netty/netty-buffer/4.1.115.Final/netty-buffer-4.1.115.Final.jar (libraries:io.netty:netty-buffer:4.1.115.Final) to libraries/io/netty/netty-buffer/4.1.115.Final/netty-buffer-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-codec/4.1.115.Final/netty-codec-4.1.115.Final.jar (libraries:io.netty:netty-codec:4.1.115.Final) to libraries/io/netty/netty-codec/4.1.115.Final/netty-codec-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-common/4.1.115.Final/netty-common-4.1.115.Final.jar (libraries:io.netty:netty-common:4.1.115.Final) to libraries/io/netty/netty-common/4.1.115.Final/netty-common-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-handler/4.1.115.Final/netty-handler-4.1.115.Final.jar (libraries:io.netty:netty-handler:4.1.115.Final) to libraries/io/netty/netty-handler/4.1.115.Final/netty-handler-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-resolver/4.1.115.Final/netty-resolver-4.1.115.Final.jar (libraries:io.netty:netty-resolver:4.1.115.Final) to libraries/io/netty/netty-resolver/4.1.115.Final/netty-resolver-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-transport/4.1.115.Final/netty-transport-4.1.115.Final.jar (libraries:io.netty:netty-transport:4.1.115.Final) to libraries/io/netty/netty-transport/4.1.115.Final/netty-transport-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-transport-classes-epoll/4.1.115.Final/netty-transport-classes-epoll-4.1.115.Final.jar (libraries:io.netty:netty-transport-classes-epoll:4.1.115.Final) to libraries/io/netty/netty-transport-classes-epoll/4.1.115.Final/netty-transport-classes-epoll-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-x86_64.jar (libraries:io.netty:netty-transport-native-epoll:4.1.115.Final:linux-x86_64) to libraries/io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-x86_64.jar
|
|
||||||
Unpacking io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-aarch_64.jar (libraries:io.netty:netty-transport-native-epoll:4.1.115.Final:linux-aarch_64) to libraries/io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-aarch_64.jar
|
|
||||||
Unpacking io/netty/netty-transport-native-unix-common/4.1.115.Final/netty-transport-native-unix-common-4.1.115.Final.jar (libraries:io.netty:netty-transport-native-unix-common:4.1.115.Final) to libraries/io/netty/netty-transport-native-unix-common/4.1.115.Final/netty-transport-native-unix-common-4.1.115.Final.jar
|
|
||||||
Unpacking it/unimi/dsi/fastutil/8.5.15/fastutil-8.5.15.jar (libraries:it.unimi.dsi:fastutil:8.5.15) to libraries/it/unimi/dsi/fastutil/8.5.15/fastutil-8.5.15.jar
|
|
||||||
Unpacking net/java/dev/jna/jna/5.15.0/jna-5.15.0.jar (libraries:net.java.dev.jna:jna:5.15.0) to libraries/net/java/dev/jna/jna/5.15.0/jna-5.15.0.jar
|
|
||||||
Unpacking net/java/dev/jna/jna-platform/5.15.0/jna-platform-5.15.0.jar (libraries:net.java.dev.jna:jna-platform:5.15.0) to libraries/net/java/dev/jna/jna-platform/5.15.0/jna-platform-5.15.0.jar
|
|
||||||
Unpacking net/minidev/accessors-smart/2.5.1/accessors-smart-2.5.1.jar (libraries:net.minidev:accessors-smart:2.5.1) to libraries/net/minidev/accessors-smart/2.5.1/accessors-smart-2.5.1.jar
|
|
||||||
Unpacking net/minidev/json-smart/2.5.1/json-smart-2.5.1.jar (libraries:net.minidev:json-smart:2.5.1) to libraries/net/minidev/json-smart/2.5.1/json-smart-2.5.1.jar
|
|
||||||
Unpacking net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar (libraries:net.sf.jopt-simple:jopt-simple:5.0.4) to libraries/net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar
|
|
||||||
Unpacking org/apache/commons/commons-lang3/3.17.0/commons-lang3-3.17.0.jar (libraries:org.apache.commons:commons-lang3:3.17.0) to libraries/org/apache/commons/commons-lang3/3.17.0/commons-lang3-3.17.0.jar
|
|
||||||
Unpacking org/apache/logging/log4j/log4j-api/2.24.1/log4j-api-2.24.1.jar (libraries:org.apache.logging.log4j:log4j-api:2.24.1) to libraries/org/apache/logging/log4j/log4j-api/2.24.1/log4j-api-2.24.1.jar
|
|
||||||
Unpacking org/apache/logging/log4j/log4j-core/2.24.1/log4j-core-2.24.1.jar (libraries:org.apache.logging.log4j:log4j-core:2.24.1) to libraries/org/apache/logging/log4j/log4j-core/2.24.1/log4j-core-2.24.1.jar
|
|
||||||
Unpacking org/apache/logging/log4j/log4j-slf4j2-impl/2.24.1/log4j-slf4j2-impl-2.24.1.jar (libraries:org.apache.logging.log4j:log4j-slf4j2-impl:2.24.1) to libraries/org/apache/logging/log4j/log4j-slf4j2-impl/2.24.1/log4j-slf4j2-impl-2.24.1.jar
|
|
||||||
Unpacking org/joml/joml/1.10.8/joml-1.10.8.jar (libraries:org.joml:joml:1.10.8) to libraries/org/joml/joml/1.10.8/joml-1.10.8.jar
|
|
||||||
Unpacking org/lz4/lz4-java/1.8.0/lz4-java-1.8.0.jar (libraries:org.lz4:lz4-java:1.8.0) to libraries/org/lz4/lz4-java/1.8.0/lz4-java-1.8.0.jar
|
|
||||||
Unpacking org/ow2/asm/asm/9.6/asm-9.6.jar (libraries:org.ow2.asm:asm:9.6) to libraries/org/ow2/asm/asm/9.6/asm-9.6.jar
|
|
||||||
Unpacking org/slf4j/slf4j-api/2.0.16/slf4j-api-2.0.16.jar (libraries:org.slf4j:slf4j-api:2.0.16) to libraries/org/slf4j/slf4j-api/2.0.16/slf4j-api-2.0.16.jar
|
|
||||||
Starting net.minecraft.server.Main
|
|
||||||
[18:02:07] [ServerMain/INFO]: Environment: Environment[sessionHost=https://sessionserver.mojang.com, servicesHost=https://api.minecraftservices.com, name=PROD]
|
|
||||||
[18:02:09] [ServerMain/INFO]: No existing world data, creating new world
|
|
||||||
[18:02:10] [ServerMain/INFO]: Loaded 1370 recipes
|
|
||||||
[18:02:10] [ServerMain/INFO]: Loaded 1481 advancements
|
|
||||||
[18:02:10] [Server thread/INFO]: Starting minecraft server version 1.21.4
|
|
||||||
[18:02:10] [Server thread/INFO]: Loading properties
|
|
||||||
[18:02:10] [Server thread/INFO]: Default game type: SURVIVAL
|
|
||||||
[18:02:10] [Server thread/INFO]: Generating keypair
|
|
||||||
[18:02:10] [Server thread/INFO]: Starting Minecraft server on *:25565
|
|
||||||
[18:02:11] [Server thread/INFO]: Using epoll channel type
|
|
||||||
[18:02:11] [Server thread/INFO]: Preparing level "world"
|
|
||||||
[18:02:21] [Server thread/INFO]: Preparing start region for dimension minecraft:overworld
|
|
||||||
[18:02:21] [Worker-Main-3/INFO]: Preparing spawn area: 2%
|
|
||||||
[18:02:21] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
|
||||||
[18:02:22] [Worker-Main-3/INFO]: Preparing spawn area: 2%
|
|
||||||
[18:02:22] [Worker-Main-3/INFO]: Preparing spawn area: 2%
|
|
||||||
[18:02:23] [Worker-Main-3/INFO]: Preparing spawn area: 12%
|
|
||||||
[18:02:23] [Worker-Main-2/INFO]: Preparing spawn area: 18%
|
|
||||||
[18:02:24] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
|
||||||
[18:02:24] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
|
||||||
[18:02:25] [Worker-Main-2/INFO]: Preparing spawn area: 28%
|
|
||||||
[18:02:26] [Worker-Main-2/INFO]: Preparing spawn area: 51%
|
|
||||||
[18:02:26] [Worker-Main-1/INFO]: Preparing spawn area: 51%
|
|
||||||
[18:02:26] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
|
||||||
[18:02:27] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
|
||||||
[18:02:27] [Server thread/INFO]: Time elapsed: 6164 ms
|
|
||||||
[18:02:27] [Server thread/INFO]: Done (16.414s)! For help, type "help"
|
|
||||||
[18:02:27] [Server thread/INFO]: Starting remote control listener
|
|
||||||
[18:02:27] [Server thread/INFO]: Thread RCON Listener started
|
|
||||||
[18:02:27] [Server thread/INFO]: RCON running on 0.0.0.0:25575
|
|
||||||
[18:03:27] [Server thread/INFO]: Server empty for 60 seconds, pausing
|
|
||||||
[18:04:23] [Server thread/INFO]: Stopping the server
|
|
||||||
[18:04:23] [Server thread/INFO]: Stopping server
|
|
||||||
[18:04:23] [Server thread/INFO]: Saving players
|
|
||||||
[18:04:23] [Server thread/INFO]: Saving worlds
|
|
||||||
[18:04:24] [Server thread/INFO]: Saving chunks for level 'ServerLevel[world]'/minecraft:overworld
|
|
||||||
[18:04:28] [Server thread/INFO]: Saving chunks for level 'ServerLevel[world]'/minecraft:the_end
|
|
||||||
[18:04:28] [Server thread/INFO]: Saving chunks for level 'ServerLevel[world]'/minecraft:the_nether
|
|
||||||
[18:04:28] [Server thread/INFO]: ThreadedAnvilChunkStorage (world): All chunks are saved
|
|
||||||
[18:04:28] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM1): All chunks are saved
|
|
||||||
[18:04:28] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM-1): All chunks are saved
|
|
||||||
[18:04:28] [Server thread/INFO]: ThreadedAnvilChunkStorage: All dimensions are saved
|
|
||||||
[18:04:28] [Server thread/INFO]: Thread RCON Listener stopped`,
|
|
||||||
`[Log4jPatcher] [INFO] Transforming org/apache/logging/log4j/core/lookup/JndiLookup
|
|
||||||
[Log4jPatcher] [INFO] Transforming org/apache/logging/log4j/core/pattern/MessagePatternConverter
|
|
||||||
[Log4jPatcher] [WARN] Unable to find noLookups:Z field in org/apache/logging/log4j/core/pattern/MessagePatternConverter
|
|
||||||
Jan 19, 2025 6:36:38 PM io.netty.util.internal.PlatformDependent <clinit>
|
|
||||||
INFO: Your platform does not provide complete low-level API for accessing direct buffers reliably. Unless explicitly requested, heap buffer will always be preferred to avoid potential system unstability.
|
|
||||||
[18:36:38] [Server thread/INFO]: Starting minecraft server version 1.7.10
|
|
||||||
[18:36:38] [Server thread/INFO]: Loading properties
|
|
||||||
[18:36:38] [Server thread/INFO]: Default game type: SURVIVAL
|
|
||||||
[18:36:38] [Server thread/INFO]: Generating keypair
|
|
||||||
[18:36:38] [Server thread/INFO]: Starting Minecraft server on *:25565
|
|
||||||
[18:36:38] [Server thread/WARN]: Failed to load user banlist:
|
|
||||||
java.io.FileNotFoundException: banned-players.json (No such file or directory)
|
|
||||||
at java.base/java.io.FileInputStream.open0(Native Method) ~[?:?]
|
|
||||||
at java.base/java.io.FileInputStream.open(Unknown Source) ~[?:?]
|
|
||||||
at java.base/java.io.FileInputStream.<init>(Unknown Source) ~[?:?]
|
|
||||||
at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.7.10.jar:?]
|
|
||||||
at om.g(SourceFile:124) ~[minecraft_server.1.7.10.jar:?]
|
|
||||||
at ls.y(SourceFile:99) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at ls.<init>(SourceFile:25) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at lt.e(SourceFile:166) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at net.minecraft.server.MinecraftServer.run(SourceFile:339) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at lj.run(SourceFile:628) [minecraft_server.1.7.10.jar:?]
|
|
||||||
[18:36:38] [Server thread/WARN]: Failed to load ip banlist:
|
|
||||||
java.io.FileNotFoundException: banned-ips.json (No such file or directory)
|
|
||||||
at java.base/java.io.FileInputStream.open0(Native Method) ~[?:?]
|
|
||||||
at java.base/java.io.FileInputStream.open(Unknown Source) ~[?:?]
|
|
||||||
at java.base/java.io.FileInputStream.<init>(Unknown Source) ~[?:?]
|
|
||||||
at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.7.10.jar:?]
|
|
||||||
at om.g(SourceFile:124) ~[minecraft_server.1.7.10.jar:?]
|
|
||||||
at ls.x(SourceFile:91) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at ls.<init>(SourceFile:27) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at lt.e(SourceFile:166) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at net.minecraft.server.MinecraftServer.run(SourceFile:339) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at lj.run(SourceFile:628) [minecraft_server.1.7.10.jar:?]
|
|
||||||
[18:36:38] [Server thread/WARN]: Failed to load operators list:
|
|
||||||
java.io.FileNotFoundException: ops.json (No such file or directory)
|
|
||||||
at java.base/java.io.FileInputStream.open0(Native Method) ~[?:?]
|
|
||||||
at java.base/java.io.FileInputStream.open(Unknown Source) ~[?:?]
|
|
||||||
at java.base/java.io.FileInputStream.<init>(Unknown Source) ~[?:?]
|
|
||||||
at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.7.10.jar:?]
|
|
||||||
at om.g(SourceFile:124) ~[minecraft_server.1.7.10.jar:?]
|
|
||||||
at ls.z(SourceFile:107) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at ls.<init>(SourceFile:29) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at lt.e(SourceFile:166) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at net.minecraft.server.MinecraftServer.run(SourceFile:339) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at lj.run(SourceFile:628) [minecraft_server.1.7.10.jar:?]
|
|
||||||
[18:36:38] [Server thread/WARN]: Failed to load white-list:
|
|
||||||
java.io.FileNotFoundException: whitelist.json (No such file or directory)
|
|
||||||
at java.base/java.io.FileInputStream.open0(Native Method) ~[?:?]
|
|
||||||
at java.base/java.io.FileInputStream.open(Unknown Source) ~[?:?]
|
|
||||||
at java.base/java.io.FileInputStream.<init>(Unknown Source) ~[?:?]
|
|
||||||
at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.7.10.jar:?]
|
|
||||||
at om.g(SourceFile:124) ~[minecraft_server.1.7.10.jar:?]
|
|
||||||
at ls.B(SourceFile:123) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at ls.<init>(SourceFile:30) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at lt.e(SourceFile:166) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at net.minecraft.server.MinecraftServer.run(SourceFile:339) [minecraft_server.1.7.10.jar:?]
|
|
||||||
at lj.run(SourceFile:628) [minecraft_server.1.7.10.jar:?]
|
|
||||||
[18:36:38] [Server thread/INFO]: Preparing level "world"
|
|
||||||
[18:36:38] [Server thread/INFO]: Preparing start region for level 0
|
|
||||||
[18:36:39] [Server thread/INFO]: Preparing spawn area: 12%
|
|
||||||
[18:36:40] [Server thread/INFO]: Preparing spawn area: 28%
|
|
||||||
[18:36:41] [Server thread/INFO]: Preparing spawn area: 48%
|
|
||||||
[18:36:42] [Server thread/INFO]: Preparing spawn area: 69%
|
|
||||||
[18:36:43] [Server thread/INFO]: Preparing spawn area: 91%
|
|
||||||
[18:36:44] [Server thread/INFO]: Done (5.518s)! For help, type "help" or "?"
|
|
||||||
[18:36:44] [Server thread/INFO]: Starting remote control listener
|
|
||||||
[18:36:44] [RCON Listener #1/INFO]: RCON running on 0.0.0.0:25575`,
|
|
||||||
`Unpacking 1.21.4/server-1.21.4.jar (versions:1.21.4) to versions/1.21.4/server-1.21.4.jar
|
|
||||||
Unpacking com/fasterxml/jackson/core/jackson-annotations/2.13.4/jackson-annotations-2.13.4.jar (libraries:com.fasterxml.jackson.core:jackson-annotations:2.13.4) to libraries/com/fasterxml/jackson/core/jackson-annotations/2.13.4/jackson-annotations-2.13.4.jar
|
|
||||||
Unpacking com/fasterxml/jackson/core/jackson-core/2.13.4/jackson-core-2.13.4.jar (libraries:com.fasterxml.jackson.core:jackson-core:2.13.4) to libraries/com/fasterxml/jackson/core/jackson-core/2.13.4/jackson-core-2.13.4.jar
|
|
||||||
Unpacking com/fasterxml/jackson/core/jackson-databind/2.13.4.2/jackson-databind-2.13.4.2.jar (libraries:com.fasterxml.jackson.core:jackson-databind:2.13.4.2) to libraries/com/fasterxml/jackson/core/jackson-databind/2.13.4.2/jackson-databind-2.13.4.2.jar
|
|
||||||
Unpacking com/github/oshi/oshi-core/6.6.5/oshi-core-6.6.5.jar (libraries:com.github.oshi:oshi-core:6.6.5) to libraries/com/github/oshi/oshi-core/6.6.5/oshi-core-6.6.5.jar
|
|
||||||
Unpacking com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar (libraries:com.github.stephenc.jcip:jcip-annotations:1.0-1) to libraries/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar
|
|
||||||
Unpacking com/google/code/gson/gson/2.11.0/gson-2.11.0.jar (libraries:com.google.code.gson:gson:2.11.0) to libraries/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar
|
|
||||||
Unpacking com/google/guava/failureaccess/1.0.2/failureaccess-1.0.2.jar (libraries:com.google.guava:failureaccess:1.0.2) to libraries/com/google/guava/failureaccess/1.0.2/failureaccess-1.0.2.jar
|
|
||||||
Unpacking com/google/guava/guava/33.3.1-jre/guava-33.3.1-jre.jar (libraries:com.google.guava:guava:33.3.1-jre) to libraries/com/google/guava/guava/33.3.1-jre/guava-33.3.1-jre.jar
|
|
||||||
Unpacking com/microsoft/azure/msal4j/1.17.2/msal4j-1.17.2.jar (libraries:com.microsoft.azure:msal4j:1.17.2) to libraries/com/microsoft/azure/msal4j/1.17.2/msal4j-1.17.2.jar
|
|
||||||
Unpacking com/mojang/authlib/6.0.57/authlib-6.0.57.jar (libraries:com.mojang:authlib:6.0.57) to libraries/com/mojang/authlib/6.0.57/authlib-6.0.57.jar
|
|
||||||
Unpacking com/mojang/brigadier/1.3.10/brigadier-1.3.10.jar (libraries:com.mojang:brigadier:1.3.10) to libraries/com/mojang/brigadier/1.3.10/brigadier-1.3.10.jar
|
|
||||||
Unpacking com/mojang/datafixerupper/8.0.16/datafixerupper-8.0.16.jar (libraries:com.mojang:datafixerupper:8.0.16) to libraries/com/mojang/datafixerupper/8.0.16/datafixerupper-8.0.16.jar
|
|
||||||
Unpacking com/mojang/jtracy/1.0.29/jtracy-1.0.29.jar (libraries:com.mojang:jtracy:1.0.29) to libraries/com/mojang/jtracy/1.0.29/jtracy-1.0.29.jar
|
|
||||||
Unpacking com/mojang/logging/1.5.10/logging-1.5.10.jar (libraries:com.mojang:logging:1.5.10) to libraries/com/mojang/logging/1.5.10/logging-1.5.10.jar
|
|
||||||
Unpacking com/nimbusds/content-type/2.3/content-type-2.3.jar (libraries:com.nimbusds:content-type:2.3) to libraries/com/nimbusds/content-type/2.3/content-type-2.3.jar
|
|
||||||
Unpacking com/nimbusds/lang-tag/1.7/lang-tag-1.7.jar (libraries:com.nimbusds:lang-tag:1.7) to libraries/com/nimbusds/lang-tag/1.7/lang-tag-1.7.jar
|
|
||||||
Unpacking com/nimbusds/nimbus-jose-jwt/9.40/nimbus-jose-jwt-9.40.jar (libraries:com.nimbusds:nimbus-jose-jwt:9.40) to libraries/com/nimbusds/nimbus-jose-jwt/9.40/nimbus-jose-jwt-9.40.jar
|
|
||||||
Unpacking com/nimbusds/oauth2-oidc-sdk/11.18/oauth2-oidc-sdk-11.18.jar (libraries:com.nimbusds:oauth2-oidc-sdk:11.18) to libraries/com/nimbusds/oauth2-oidc-sdk/11.18/oauth2-oidc-sdk-11.18.jar
|
|
||||||
Unpacking commons-io/commons-io/2.17.0/commons-io-2.17.0.jar (libraries:commons-io:commons-io:2.17.0) to libraries/commons-io/commons-io/2.17.0/commons-io-2.17.0.jar
|
|
||||||
Unpacking io/netty/netty-buffer/4.1.115.Final/netty-buffer-4.1.115.Final.jar (libraries:io.netty:netty-buffer:4.1.115.Final) to libraries/io/netty/netty-buffer/4.1.115.Final/netty-buffer-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-codec/4.1.115.Final/netty-codec-4.1.115.Final.jar (libraries:io.netty:netty-codec:4.1.115.Final) to libraries/io/netty/netty-codec/4.1.115.Final/netty-codec-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-common/4.1.115.Final/netty-common-4.1.115.Final.jar (libraries:io.netty:netty-common:4.1.115.Final) to libraries/io/netty/netty-common/4.1.115.Final/netty-common-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-handler/4.1.115.Final/netty-handler-4.1.115.Final.jar (libraries:io.netty:netty-handler:4.1.115.Final) to libraries/io/netty/netty-handler/4.1.115.Final/netty-handler-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-resolver/4.1.115.Final/netty-resolver-4.1.115.Final.jar (libraries:io.netty:netty-resolver:4.1.115.Final) to libraries/io/netty/netty-resolver/4.1.115.Final/netty-resolver-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-transport/4.1.115.Final/netty-transport-4.1.115.Final.jar (libraries:io.netty:netty-transport:4.1.115.Final) to libraries/io/netty/netty-transport/4.1.115.Final/netty-transport-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-transport-classes-epoll/4.1.115.Final/netty-transport-classes-epoll-4.1.115.Final.jar (libraries:io.netty:netty-transport-classes-epoll:4.1.115.Final) to libraries/io/netty/netty-transport-classes-epoll/4.1.115.Final/netty-transport-classes-epoll-4.1.115.Final.jar
|
|
||||||
Unpacking io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-x86_64.jar (libraries:io.netty:netty-transport-native-epoll:4.1.115.Final:linux-x86_64) to libraries/io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-x86_64.jar
|
|
||||||
Unpacking io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-aarch_64.jar (libraries:io.netty:netty-transport-native-epoll:4.1.115.Final:linux-aarch_64) to libraries/io/netty/netty-transport-native-epoll/4.1.115.Final/netty-transport-native-epoll-4.1.115.Final-linux-aarch_64.jar
|
|
||||||
Unpacking io/netty/netty-transport-native-unix-common/4.1.115.Final/netty-transport-native-unix-common-4.1.115.Final.jar (libraries:io.netty:netty-transport-native-unix-common:4.1.115.Final) to libraries/io/netty/netty-transport-native-unix-common/4.1.115.Final/netty-transport-native-unix-common-4.1.115.Final.jar
|
|
||||||
Unpacking it/unimi/dsi/fastutil/8.5.15/fastutil-8.5.15.jar (libraries:it.unimi.dsi:fastutil:8.5.15) to libraries/it/unimi/dsi/fastutil/8.5.15/fastutil-8.5.15.jar
|
|
||||||
Unpacking net/java/dev/jna/jna/5.15.0/jna-5.15.0.jar (libraries:net.java.dev.jna:jna:5.15.0) to libraries/net/java/dev/jna/jna/5.15.0/jna-5.15.0.jar
|
|
||||||
Unpacking net/java/dev/jna/jna-platform/5.15.0/jna-platform-5.15.0.jar (libraries:net.java.dev.jna:jna-platform:5.15.0) to libraries/net/java/dev/jna/jna-platform/5.15.0/jna-platform-5.15.0.jar
|
|
||||||
Unpacking net/minidev/accessors-smart/2.5.1/accessors-smart-2.5.1.jar (libraries:net.minidev:accessors-smart:2.5.1) to libraries/net/minidev/accessors-smart/2.5.1/accessors-smart-2.5.1.jar
|
|
||||||
Unpacking net/minidev/json-smart/2.5.1/json-smart-2.5.1.jar (libraries:net.minidev:json-smart:2.5.1) to libraries/net/minidev/json-smart/2.5.1/json-smart-2.5.1.jar
|
|
||||||
Unpacking net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar (libraries:net.sf.jopt-simple:jopt-simple:5.0.4) to libraries/net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar
|
|
||||||
Unpacking org/apache/commons/commons-lang3/3.17.0/commons-lang3-3.17.0.jar (libraries:org.apache.commons:commons-lang3:3.17.0) to libraries/org/apache/commons/commons-lang3/3.17.0/commons-lang3-3.17.0.jar
|
|
||||||
Unpacking org/apache/logging/log4j/log4j-api/2.24.1/log4j-api-2.24.1.jar (libraries:org.apache.logging.log4j:log4j-api:2.24.1) to libraries/org/apache/logging/log4j/log4j-api/2.24.1/log4j-api-2.24.1.jar
|
|
||||||
Unpacking org/apache/logging/log4j/log4j-core/2.24.1/log4j-core-2.24.1.jar (libraries:org.apache.logging.log4j:log4j-core:2.24.1) to libraries/org/apache/logging/log4j/log4j-core/2.24.1/log4j-core-2.24.1.jar
|
|
||||||
Unpacking org/apache/logging/log4j/log4j-slf4j2-impl/2.24.1/log4j-slf4j2-impl-2.24.1.jar (libraries:org.apache.logging.log4j:log4j-slf4j2-impl:2.24.1) to libraries/org/apache/logging/log4j/log4j-slf4j2-impl/2.24.1/log4j-slf4j2-impl-2.24.1.jar
|
|
||||||
Unpacking org/joml/joml/1.10.8/joml-1.10.8.jar (libraries:org.joml:joml:1.10.8) to libraries/org/joml/joml/1.10.8/joml-1.10.8.jar
|
|
||||||
Unpacking org/lz4/lz4-java/1.8.0/lz4-java-1.8.0.jar (libraries:org.lz4:lz4-java:1.8.0) to libraries/org/lz4/lz4-java/1.8.0/lz4-java-1.8.0.jar
|
|
||||||
Unpacking org/ow2/asm/asm/9.6/asm-9.6.jar (libraries:org.ow2.asm:asm:9.6) to libraries/org/ow2/asm/asm/9.6/asm-9.6.jar
|
|
||||||
Unpacking org/slf4j/slf4j-api/2.0.16/slf4j-api-2.0.16.jar (libraries:org.slf4j:slf4j-api:2.0.16) to libraries/org/slf4j/slf4j-api/2.0.16/slf4j-api-2.0.16.jar
|
|
||||||
Starting net.minecraft.server.Main
|
|
||||||
[21:40:55] [ServerMain/INFO]: Environment: Environment[sessionHost=https://sessionserver.mojang.com, servicesHost=https://api.minecraftservices.com, name=PROD]
|
|
||||||
[21:40:59] [ServerMain/INFO]: No existing world data, creating new world
|
|
||||||
[21:41:01] [ServerMain/INFO]: Loaded 1370 recipes
|
|
||||||
[21:41:01] [ServerMain/INFO]: Loaded 1481 advancements
|
|
||||||
[21:41:01] [Server thread/INFO]: Starting minecraft server version 1.21.4
|
|
||||||
[21:41:01] [Server thread/INFO]: Loading properties
|
|
||||||
[21:41:01] [Server thread/INFO]: Default game type: SURVIVAL
|
|
||||||
[21:41:01] [Server thread/INFO]: Generating keypair
|
|
||||||
[21:41:01] [Server thread/INFO]: Starting Minecraft server on *:25565
|
|
||||||
[21:41:02] [Server thread/INFO]: Using epoll channel type
|
|
||||||
[21:41:02] [Server thread/INFO]: Preparing level "world"
|
|
||||||
[21:41:22] [Server thread/INFO]: Preparing start region for dimension minecraft:overworld
|
|
||||||
[21:41:23] [Worker-Main-2/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:23] [Worker-Main-2/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:24] [Worker-Main-2/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:24] [Worker-Main-3/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:24] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:25] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:25] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:26] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:26] [Worker-Main-3/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:27] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:27] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:28] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:28] [Worker-Main-1/INFO]: Preparing spawn area: 2%
|
|
||||||
[21:41:29] [Worker-Main-3/INFO]: Preparing spawn area: 8%
|
|
||||||
[21:41:30] [Worker-Main-2/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:30] [Worker-Main-2/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:30] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:31] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:31] [Worker-Main-3/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:32] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:32] [Worker-Main-1/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:33] [Worker-Main-3/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:33] [Worker-Main-3/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:34] [Worker-Main-3/INFO]: Preparing spawn area: 18%
|
|
||||||
[21:41:34] [Worker-Main-3/INFO]: Preparing spawn area: 20%
|
|
||||||
[21:41:35] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:35] [Worker-Main-1/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:36] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:36] [Worker-Main-2/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:37] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:37] [Worker-Main-1/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:38] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:38] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:39] [Worker-Main-3/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:39] [Worker-Main-2/INFO]: Preparing spawn area: 51%
|
|
||||||
[21:41:40] [Server thread/INFO]: Time elapsed: 17596 ms
|
|
||||||
[21:41:40] [Server thread/INFO]: Done (38.008s)! For help, type "help"
|
|
||||||
[21:41:40] [Server thread/INFO]: Starting remote control listener
|
|
||||||
[21:41:40] [Server thread/INFO]: Thread RCON Listener started
|
|
||||||
[21:41:40] [Server thread/INFO]: RCON running on 0.0.0.0:25575
|
|
||||||
[21:42:17] [User Authenticator #1/INFO]: UUID of player Sirherobrine23 is 0dc9df8f-9f5a-45d8-8848-9262a4357ae0
|
|
||||||
[21:42:20] [Server thread/INFO]: Sirherobrine23[/[0:0:0:0:0:0:0:1]:54662] logged in with entity id 41 at (37.5, 76.0, -57.5)
|
|
||||||
[21:42:20] [Server thread/INFO]: Sirherobrine23 joined the game
|
|
||||||
[21:43:42] [Server thread/WARN]: Sirherobrine23 moved too quickly! 9.663497831602484,3.176759275064242,0.8707508869438136
|
|
||||||
[21:43:42] [Server thread/WARN]: Can't keep up! Is the server overloaded? Running 4510ms or 90 ticks behind
|
|
||||||
[21:45:18] [Server thread/INFO]: Sirherobrine23 lost connection: Disconnected
|
|
||||||
[21:45:18] [Server thread/INFO]: Sirherobrine23 left the game`,
|
|
||||||
}
|
|
||||||
)
|
|
178
mclog/server.go
178
mclog/server.go
@ -1,178 +0,0 @@
|
|||||||
package mclog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"slices"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Storage interface {
|
|
||||||
fs.FS
|
|
||||||
Remove(name string) error // Remove file from storage
|
|
||||||
Create(name string) (io.WriteCloser, error) // Save file in storage
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeJSON(w io.Writer, obj any) {
|
|
||||||
enc := json.NewEncoder(w)
|
|
||||||
enc.SetIndent("", " ")
|
|
||||||
enc.Encode(obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeErr(w http.ResponseWriter, err error) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
if errors.Is(err, fs.ErrNotExist) {
|
|
||||||
w.WriteHeader(404)
|
|
||||||
writeJSON(w, MclogResponseStatus{Success: false, ErrorMessage: ErrNoExists.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.WriteHeader(500)
|
|
||||||
writeJSON(w, MclogResponseStatus{Success: false, ErrorMessage: err.Error()})
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(serverLimits Limits, storage Storage) *http.ServeMux {
|
|
||||||
control := http.NewServeMux()
|
|
||||||
|
|
||||||
// Return server limits to process logs
|
|
||||||
control.HandleFunc("GET /1/limits", func(w http.ResponseWriter, _ *http.Request) {
|
|
||||||
w.WriteHeader(200)
|
|
||||||
writeJSON(w, Limits{
|
|
||||||
StorageTime: serverLimits.StorageTime / time.Second, // return only seconds
|
|
||||||
MaxLength: serverLimits.MaxLength,
|
|
||||||
MaxLines: serverLimits.MaxLines,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Get log stream
|
|
||||||
control.HandleFunc("GET /1/raw/{id}", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
logId := r.PathValue("id")
|
|
||||||
body, err := storage.Open(logId)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, fs.ErrNotExist) {
|
|
||||||
w.WriteHeader(404)
|
|
||||||
writeJSON(w, MclogResponseStatus{Success: false, ErrorMessage: ErrNoExists.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.WriteHeader(500)
|
|
||||||
writeJSON(w, MclogResponseStatus{Success: false, ErrorMessage: err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer body.Close()
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain") // Set file stream
|
|
||||||
if stat, err := body.Stat(); err == nil {
|
|
||||||
w.Header().Set("content-length", strconv.FormatInt(stat.Size(), 10))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response
|
|
||||||
w.WriteHeader(200)
|
|
||||||
go io.Copy(w, body)
|
|
||||||
})
|
|
||||||
|
|
||||||
control.HandleFunc("GET /1/insights/{id}", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
logId := r.PathValue("id") // get log id
|
|
||||||
|
|
||||||
// Open log file
|
|
||||||
logBody, err := storage.Open(logId)
|
|
||||||
if err != nil {
|
|
||||||
writeErr(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer logBody.Close()
|
|
||||||
|
|
||||||
// Parse log body
|
|
||||||
logInsight, err := ParseLog(logBody);
|
|
||||||
if err != nil {
|
|
||||||
writeErr(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// return log insight
|
|
||||||
w.WriteHeader(200)
|
|
||||||
writeJSON(w, logInsight)
|
|
||||||
})
|
|
||||||
|
|
||||||
control.HandleFunc("POST /1/log", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// Close body after run function
|
|
||||||
defer r.Body.Close()
|
|
||||||
|
|
||||||
// Set only reader type
|
|
||||||
logStream := io.Reader(r.Body)
|
|
||||||
if serverLimits.MaxLength > 0 {
|
|
||||||
logStream = io.LimitReader(r.Body, serverLimits.MaxLength) // Set max body lenght from limits
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case slices.Contains(r.Header.Values("Content-Type"), "application/octet-stream"):
|
|
||||||
// noop, only reader body from logStream
|
|
||||||
case slices.Contains(r.Header.Values("Content-Type"), "application/x-www-form-urlencoded"):
|
|
||||||
// Read all body
|
|
||||||
body, err := io.ReadAll(logStream)
|
|
||||||
if err != nil {
|
|
||||||
writeErr(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse body
|
|
||||||
form, err := url.ParseQuery(string(body))
|
|
||||||
if err != nil {
|
|
||||||
writeErr(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if body have "content"
|
|
||||||
if !form.Has("content") {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
writeJSON(w, MclogResponseStatus{Success: false, ErrorMessage: "require the 'content' in body"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attemp write log file
|
|
||||||
logStream = strings.NewReader(form.Get("content"))
|
|
||||||
default:
|
|
||||||
w.WriteHeader(400)
|
|
||||||
writeJSON(w, MclogResponseStatus{Success: false, ErrorMessage: "Require 'application/x-www-form-urlencoded' or raw stream/'application/octet-stream'"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var randomId string
|
|
||||||
for randomId == "" {
|
|
||||||
buff := make([]byte, 8)
|
|
||||||
if _, err := rand.Read(buff); err != nil {
|
|
||||||
writeErr(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
randomId = hex.EncodeToString(buff)
|
|
||||||
if f, err := storage.Open(randomId); err == nil {
|
|
||||||
f.Close() // Close file
|
|
||||||
randomId = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attemp write log file
|
|
||||||
file, err := storage.Create(randomId)
|
|
||||||
if err != nil {
|
|
||||||
writeErr(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
if _, err = io.Copy(file, logStream); err != nil {
|
|
||||||
writeErr(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write success log id
|
|
||||||
w.WriteHeader(201)
|
|
||||||
writeJSON(w, MclogResponseStatus{Success: true, Id: randomId})
|
|
||||||
})
|
|
||||||
|
|
||||||
return control
|
|
||||||
}
|
|
Reference in New Issue
Block a user