1// Copyright 2015 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14// +build !windows,!nacl,!plan9 15 16package log 17 18import ( 19 "fmt" 20 "log/syslog" 21 "os" 22 23 "github.com/sirupsen/logrus" 24) 25 26var _ logrus.Formatter = (*syslogger)(nil) 27 28func init() { 29 setSyslogFormatter = func(l logger, appname, local string) error { 30 if appname == "" { 31 return fmt.Errorf("missing appname parameter") 32 } 33 if local == "" { 34 return fmt.Errorf("missing local parameter") 35 } 36 37 fmter, err := newSyslogger(appname, local, l.entry.Logger.Formatter) 38 if err != nil { 39 fmt.Fprintf(os.Stderr, "error creating syslog formatter: %v\n", err) 40 l.entry.Errorf("can't connect logger to syslog: %v", err) 41 return err 42 } 43 l.entry.Logger.Formatter = fmter 44 return nil 45 } 46} 47 48var prefixTag []byte 49 50type syslogger struct { 51 wrap logrus.Formatter 52 out *syslog.Writer 53} 54 55func newSyslogger(appname string, facility string, fmter logrus.Formatter) (*syslogger, error) { 56 priority, err := getFacility(facility) 57 if err != nil { 58 return nil, err 59 } 60 out, err := syslog.New(priority, appname) 61 _, isJSON := fmter.(*logrus.JSONFormatter) 62 if isJSON { 63 // add cee tag to json formatted syslogs 64 prefixTag = []byte("@cee:") 65 } 66 return &syslogger{ 67 out: out, 68 wrap: fmter, 69 }, err 70} 71 72func getFacility(facility string) (syslog.Priority, error) { 73 switch facility { 74 case "0": 75 return syslog.LOG_LOCAL0, nil 76 case "1": 77 return syslog.LOG_LOCAL1, nil 78 case "2": 79 return syslog.LOG_LOCAL2, nil 80 case "3": 81 return syslog.LOG_LOCAL3, nil 82 case "4": 83 return syslog.LOG_LOCAL4, nil 84 case "5": 85 return syslog.LOG_LOCAL5, nil 86 case "6": 87 return syslog.LOG_LOCAL6, nil 88 case "7": 89 return syslog.LOG_LOCAL7, nil 90 } 91 return syslog.LOG_LOCAL0, fmt.Errorf("invalid local(%s) for syslog", facility) 92} 93 94func (s *syslogger) Format(e *logrus.Entry) ([]byte, error) { 95 data, err := s.wrap.Format(e) 96 if err != nil { 97 fmt.Fprintf(os.Stderr, "syslogger: can't format entry: %v\n", err) 98 return data, err 99 } 100 // only append tag to data sent to syslog (line), not to what 101 // is returned 102 line := string(append(prefixTag, data...)) 103 104 switch e.Level { 105 case logrus.PanicLevel: 106 err = s.out.Crit(line) 107 case logrus.FatalLevel: 108 err = s.out.Crit(line) 109 case logrus.ErrorLevel: 110 err = s.out.Err(line) 111 case logrus.WarnLevel: 112 err = s.out.Warning(line) 113 case logrus.InfoLevel: 114 err = s.out.Info(line) 115 case logrus.DebugLevel: 116 err = s.out.Debug(line) 117 default: 118 err = s.out.Notice(line) 119 } 120 121 if err != nil { 122 fmt.Fprintf(os.Stderr, "syslogger: can't send log to syslog: %v\n", err) 123 } 124 125 return data, err 126} 127