Explorar o código

Add syslog integration

Rod Hynes %!s(int64=10) %!d(string=hai) anos
pai
achega
61813fc9dd
Modificáronse 3 ficheiros con 104 adicións e 1 borrados
  1. 11 0
      psiphon/server/config.go
  2. 88 0
      psiphon/server/log.go
  3. 5 1
      psiphon/server/services.go

+ 11 - 0
psiphon/server/config.go

@@ -38,6 +38,7 @@ import (
 const (
 	SERVER_CONFIG_FILENAME                 = "psiphon-server.config"
 	SERVER_ENTRY_FILENAME                  = "serverEntry.dat"
+	DEFAULT_LOG_LEVEL                      = "Info"
 	DEFAULT_GEO_IP_DATABASE_FILENAME       = "GeoLite2-City.mmdb"
 	DEFAULT_SERVER_IP_ADDRESS              = "127.0.0.1"
 	WEB_SERVER_SECRET_BYTE_LENGTH          = 32
@@ -56,7 +57,13 @@ const (
 	DEFAULT_OBFUSCATED_SSH_SERVER_PORT     = 3333
 )
 
+// TODO: break config into sections (sub-structs)
+
 type Config struct {
+	LogLevel                string
+	SyslogAddress           string
+	SyslogFacility          string
+	SyslogTag               string
 	GeoIPDatabaseFilename   string
 	ServerIPAddress         string
 	WebServerPort           int
@@ -177,6 +184,10 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, error) {
 	// Assemble config and server entry
 
 	config := &Config{
+		LogLevel:                DEFAULT_LOG_LEVEL,
+		SyslogAddress:           "",
+		SyslogFacility:          "",
+		SyslogTag:               "",
 		GeoIPDatabaseFilename:   DEFAULT_GEO_IP_DATABASE_FILENAME,
 		ServerIPAddress:         serverIPaddress,
 		WebServerPort:           webServerPort,

+ 88 - 0
psiphon/server/log.go

@@ -21,9 +21,11 @@ package server
 
 import (
 	"io"
+	"log/syslog"
 	"os"
 
 	"github.com/Psiphon-Inc/logrus"
+	logrus_syslog "github.com/Psiphon-Inc/logrus/hooks/syslog"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
 )
 
@@ -68,6 +70,92 @@ func NewLogWriter() *io.PipeWriter {
 
 var log *ContextLogger
 
+// InitLogging configures a logger according to the specified
+// config params. If not called, the default logger set by the
+// package init() is used.
+// Concurrenty note: should only be called from the main
+// goroutine.
+func InitLogging(config *Config) error {
+
+	logLevel := DEFAULT_LOG_LEVEL
+	if config.LogLevel != "" {
+		logLevel = config.LogLevel
+	}
+
+	level, err := logrus.ParseLevel(logLevel)
+	if err != nil {
+		return psiphon.ContextError(err)
+	}
+
+	hooks := make(logrus.LevelHooks)
+
+	var syslogHook *logrus_syslog.SyslogHook
+
+	if config.SyslogAddress != "" {
+
+		syslogHook, err = logrus_syslog.NewSyslogHook(
+			"udp",
+			config.SyslogAddress,
+			getSyslogPriority(config),
+			config.SyslogTag)
+
+		if err != nil {
+			return psiphon.ContextError(err)
+		}
+
+		hooks.Add(syslogHook)
+	}
+
+	log = &ContextLogger{
+		&logrus.Logger{
+			Out:       os.Stderr,
+			Formatter: new(logrus.TextFormatter),
+			Hooks:     hooks,
+			Level:     level,
+		},
+	}
+
+	return nil
+}
+
+// getSyslogPriority determines golang's syslog "priority" value
+// based on the provided config.
+func getSyslogPriority(config *Config) syslog.Priority {
+
+	// TODO: assumes log.Level filter applies?
+	severity := syslog.LOG_DEBUG
+
+	facilityCodes := map[string]syslog.Priority{
+		"KERN":     syslog.LOG_KERN,
+		"USER":     syslog.LOG_USER,
+		"MAIL":     syslog.LOG_MAIL,
+		"DAEMON":   syslog.LOG_DAEMON,
+		"AUTH":     syslog.LOG_AUTH,
+		"SYSLOG":   syslog.LOG_SYSLOG,
+		"LPR":      syslog.LOG_LPR,
+		"NEWS":     syslog.LOG_NEWS,
+		"UUCP":     syslog.LOG_UUCP,
+		"CRON":     syslog.LOG_CRON,
+		"AUTHPRIV": syslog.LOG_AUTHPRIV,
+		"FTP":      syslog.LOG_FTP,
+		"LOCAL0":   syslog.LOG_LOCAL0,
+		"LOCAL1":   syslog.LOG_LOCAL1,
+		"LOCAL2":   syslog.LOG_LOCAL2,
+		"LOCAL3":   syslog.LOG_LOCAL3,
+		"LOCAL4":   syslog.LOG_LOCAL4,
+		"LOCAL5":   syslog.LOG_LOCAL5,
+		"LOCAL6":   syslog.LOG_LOCAL6,
+		"LOCAL7":   syslog.LOG_LOCAL7,
+	}
+
+	facility, ok := facilityCodes[config.SyslogFacility]
+	if !ok {
+		facility = syslog.LOG_USER
+	}
+
+	return severity | facility
+}
+
 func init() {
 	log = &ContextLogger{
 		&logrus.Logger{

+ 5 - 1
psiphon/server/services.go

@@ -35,7 +35,11 @@ func RunServices(encodedConfig []byte) error {
 		return psiphon.ContextError(err)
 	}
 
-	// TODO: init logging
+	err = InitLogging(config)
+	if err != nil {
+		log.WithContextFields(LogFields{"error": err}).Error("init logging failed")
+		return psiphon.ContextError(err)
+	}
 
 	err = InitGeoIP(config)
 	if err != nil {