github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/audit/auditlogfile.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package audit 5 6 import ( 7 "io" 8 "os" 9 "path/filepath" 10 "strings" 11 "time" 12 13 "fmt" 14 "github.com/juju/errors" 15 "github.com/juju/loggo" 16 "github.com/juju/utils" 17 "gopkg.in/natefinch/lumberjack.v2" 18 ) 19 20 var logger = loggo.GetLogger("juju.audit") 21 22 // NewLogFileSink returns an audit entry sink which writes 23 // to an audit.log file in the specified directory. 24 func NewLogFileSink(logDir string) AuditEntrySinkFn { 25 logPath := filepath.Join(logDir, "audit.log") 26 if err := primeLogFile(logPath); err != nil { 27 // This isn't a fatal error so log and continue if priming 28 // fails. 29 logger.Errorf("Unable to prime %s (proceeding anyway): %v", logPath, err) 30 } 31 32 handler := &auditLogFileSink{ 33 fileLogger: &lumberjack.Logger{ 34 Filename: logPath, 35 MaxSize: 300, // MB 36 MaxBackups: 10, 37 }, 38 } 39 return handler.handle 40 } 41 42 // primeLogFile ensures the logsink log file is created with the 43 // correct mode and ownership. 44 func primeLogFile(path string) error { 45 f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0600) 46 if err != nil { 47 return errors.Trace(err) 48 } 49 if err := f.Close(); err != nil { 50 return errors.Trace(err) 51 } 52 err = utils.ChownPath(path, "syslog") 53 return errors.Trace(err) 54 } 55 56 type auditLogFileSink struct { 57 fileLogger io.WriteCloser 58 } 59 60 func (a *auditLogFileSink) handle(entry AuditEntry) error { 61 _, err := a.fileLogger.Write([]byte(strings.Join([]string{ 62 entry.Timestamp.In(time.UTC).Format("2006-01-02 15:04:05"), 63 entry.ModelUUID, 64 entry.RemoteAddress, 65 entry.OriginName, 66 entry.OriginType, 67 entry.Operation, 68 fmt.Sprintf("%v", entry.Data), 69 }, ",") + "\n")) 70 return err 71 }