@@ -2,42 +2,105 @@ package main
22
33import (
44 "flag"
5+ "io"
56 "os"
67 "path/filepath"
78 "runtime/debug"
9+ "strings"
810
9- "github.com/Unity-Technologies/multiplay-examples/simple-game-server-go/internal/game"
1011 "github.com/sirupsen/logrus"
12+
13+ "github.com/Unity-Technologies/multiplay-examples/simple-game-server-go/internal/game"
1114)
1215
1316// parseFlags parses the supported flags and returns the values supplied to these flags.
1417func parseFlags (args []string ) (string , string , string , error ) {
1518 dir , _ := os .UserHomeDir ()
1619 f := flag .NewFlagSet ("simple-game-server-go" , flag .ContinueOnError )
1720
18- var log , logFile , tracebackLevel string
19- f .StringVar (& log , "log" , filepath .Join (dir , "logs" ), "path to the log directory to write to " )
21+ var logTargets , logFile , tracebackLevel string
22+ f .StringVar (& logTargets , "log" , "stdout," + filepath .Join (dir , "logs" ), "comma-separated log targets: 'stdout', file path, or directory " )
2023 f .StringVar (& logFile , "logFile" , "" , "path to the log file to write to" )
21- f .StringVar (
22- & tracebackLevel ,
23- "tracebackLevel" ,
24- "" ,
25- "the amount of detail printed by the runtime prints before exiting due to an unrecovered panic" ,
26- )
24+ f .StringVar (& tracebackLevel , "tracebackLevel" , "none" , "the amount of detail printed by the runtime prints before exiting due to an unrecovered panic" )
2725
2826 // Flags which are not used, but must be present to satisfy the default parameters in the Unity Dashboard.
2927 var port , queryPort uint
3028 f .UintVar (& port , "port" , 8000 , "port for the game server to bind to" )
3129 f .UintVar (& queryPort , "queryport" , 8001 , "port for the query endpoint to bind to" )
3230
33- return log , logFile , tracebackLevel , f .Parse (args )
31+ return logTargets , logFile , tracebackLevel , f .Parse (args )
32+ }
33+
34+ // logWritersFromTargets creates a multi-writer from the specified log targets and log file.
35+ // If no valid targets are provided, it defaults to writing to stdout.
36+ func logWritersFromTargets (logTargets string , logFile string , logger * logrus.Logger ) io.Writer {
37+ targets := make ([]io.Writer , 0 )
38+ for _ , t := range splitAndTrim (logTargets ) {
39+ switch t {
40+ case "stdout" :
41+ targets = append (targets , os .Stdout )
42+ case "stderr" :
43+ targets = append (targets , os .Stderr )
44+ default :
45+ // If it's a directory, use server.log inside it
46+ info , err := os .Stat (t )
47+ if err == nil && info .IsDir () {
48+ t = filepath .Join (t , "server.log" )
49+ }
50+ f , err := os .OpenFile (t , os .O_CREATE | os .O_WRONLY | os .O_APPEND , 0o666 )
51+ if err != nil {
52+ logger .WithError (err ).Warningf ("could not open log target %s for writing" , t )
53+ continue
54+ }
55+ targets = append (targets , f )
56+ }
57+ }
58+ // logFile takes precedence
59+ if logFile != "" {
60+ f , err := os .OpenFile (logFile , os .O_CREATE | os .O_WRONLY | os .O_APPEND , 0o666 )
61+ if err == nil {
62+ targets = append (targets , f )
63+ } else {
64+ logger .WithError (err ).Warning ("could not open log file for writing" )
65+ }
66+ }
67+ if len (targets ) == 0 {
68+ return os .Stdout
69+ }
70+ return io .MultiWriter (targets ... )
71+ }
72+
73+ // splitAndTrim splits a string by the OS-specific path list separator and trims each part.
74+ func splitAndTrim (s string ) []string {
75+ parts := make ([]string , 0 )
76+ for _ , p := range filepath .SplitList (s ) {
77+ for _ , t := range splitComma (p ) {
78+ trimmed := filepath .Clean (t )
79+ if trimmed != "" {
80+ parts = append (parts , trimmed )
81+ }
82+ }
83+ }
84+ return parts
85+ }
86+
87+ // splitComma splits a string by commas and trims each part, returning a slice of non-empty strings.
88+ func splitComma (s string ) []string {
89+ res := make ([]string , 0 )
90+ for _ , t := range strings .Split (s , "," ) {
91+ trimmed := filepath .Clean (t )
92+ if trimmed != "" {
93+ res = append (res , trimmed )
94+ }
95+ }
96+ return res
3497}
3598
3699func main () {
37100 logger := logrus .New ()
38101 logger .SetFormatter (& logrus.JSONFormatter {})
39102
40- log , logFile , tracebackLevel , err := parseFlags (os .Args [1 :])
103+ logTargets , logFile , tracebackLevel , err := parseFlags (os .Args [1 :])
41104 if err != nil {
42105 logger .WithError (err ).Fatal ("error parsing flags" )
43106 }
@@ -47,20 +110,7 @@ func main() {
47110 debug .SetTraceback (tracebackLevel )
48111 }
49112
50- // Let -logFile take precedence over -log
51- if logFile == "" && log != "" {
52- logFile = filepath .Join (log , "server.log" )
53- }
54-
55- if logFile != "" {
56- f , err := os .OpenFile (logFile , os .O_CREATE | os .O_WRONLY | os .O_APPEND , 0o666 )
57- if err == nil {
58- defer f .Close ()
59- logger .Out = f
60- } else {
61- logger .WithError (err ).Warning ("could not open log file for writing" )
62- }
63- }
113+ logger .Out = logWritersFromTargets (logTargets , logFile , logger )
64114
65115 g , err := game .New (logger )
66116 if err != nil {
0 commit comments