github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/client/driver/logging/syslog_parser_unix.go (about) 1 // +build darwin dragonfly freebsd linux netbsd openbsd solaris 2 3 package logging 4 5 import ( 6 "fmt" 7 "log" 8 "log/syslog" 9 "strconv" 10 ) 11 12 // Errors related to parsing priority 13 var ( 14 ErrPriorityNoStart = fmt.Errorf("No start char found for priority") 15 ErrPriorityEmpty = fmt.Errorf("Priority field empty") 16 ErrPriorityNoEnd = fmt.Errorf("No end char found for priority") 17 ErrPriorityTooShort = fmt.Errorf("Priority field too short") 18 ErrPriorityTooLong = fmt.Errorf("Priority field too long") 19 ErrPriorityNonDigit = fmt.Errorf("Non digit found in priority") 20 ) 21 22 // Priority header and ending characters 23 const ( 24 PRI_PART_START = '<' 25 PRI_PART_END = '>' 26 ) 27 28 // SyslogMessage represents a log line received 29 type SyslogMessage struct { 30 Message []byte 31 Severity syslog.Priority 32 } 33 34 // Priority holds all the priority bits in a syslog log line 35 type Priority struct { 36 Pri int 37 Facility syslog.Priority 38 Severity syslog.Priority 39 } 40 41 // DockerLogParser parses a line of log message that the docker daemon ships 42 type DockerLogParser struct { 43 logger *log.Logger 44 } 45 46 // NewDockerLogParser creates a new DockerLogParser 47 func NewDockerLogParser(logger *log.Logger) *DockerLogParser { 48 return &DockerLogParser{logger: logger} 49 } 50 51 // Parse parses a syslog log line 52 func (d *DockerLogParser) Parse(line []byte) *SyslogMessage { 53 pri, _, _ := d.parsePriority(line) 54 msgIdx := d.logContentIndex(line) 55 return &SyslogMessage{ 56 Severity: pri.Severity, 57 Message: line[msgIdx:], 58 } 59 } 60 61 // logContentIndex finds out the index of the start index of the content in a 62 // syslog line 63 func (d *DockerLogParser) logContentIndex(line []byte) int { 64 cursor := 0 65 numSpace := 0 66 for i := 0; i < len(line); i++ { 67 if line[i] == ' ' { 68 numSpace += 1 69 if numSpace == 1 { 70 cursor = i 71 break 72 } 73 } 74 } 75 for i := cursor; i < len(line); i++ { 76 if line[i] == ':' { 77 cursor = i 78 break 79 } 80 } 81 return cursor + 1 82 } 83 84 // parsePriority parses the priority in a syslog message 85 func (d *DockerLogParser) parsePriority(line []byte) (Priority, int, error) { 86 cursor := 0 87 pri := d.newPriority(0) 88 if len(line) <= 0 { 89 return pri, cursor, ErrPriorityEmpty 90 } 91 if line[cursor] != PRI_PART_START { 92 return pri, cursor, ErrPriorityNoStart 93 } 94 i := 1 95 priDigit := 0 96 for i < len(line) { 97 if i >= 5 { 98 return pri, cursor, ErrPriorityTooLong 99 } 100 c := line[i] 101 if c == PRI_PART_END { 102 if i == 1 { 103 return pri, cursor, ErrPriorityTooShort 104 } 105 cursor = i + 1 106 return d.newPriority(priDigit), cursor, nil 107 } 108 if d.isDigit(c) { 109 v, e := strconv.Atoi(string(c)) 110 if e != nil { 111 return pri, cursor, e 112 } 113 priDigit = (priDigit * 10) + v 114 } else { 115 return pri, cursor, ErrPriorityNonDigit 116 } 117 i++ 118 } 119 return pri, cursor, ErrPriorityNoEnd 120 } 121 122 // isDigit checks if a byte is a numeric char 123 func (d *DockerLogParser) isDigit(c byte) bool { 124 return c >= '0' && c <= '9' 125 } 126 127 // newPriority creates a new default priority 128 func (d *DockerLogParser) newPriority(p int) Priority { 129 // The Priority value is calculated by first multiplying the Facility 130 // number by 8 and then adding the numerical value of the Severity. 131 return Priority{ 132 Pri: p, 133 Facility: syslog.Priority(p / 8), 134 Severity: syslog.Priority(p % 8), 135 } 136 }