mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 23:42:26 -05:00
Add optional syslog logrus hook (#343)
* add optional syslog logrus hook * document syslog
This commit is contained in:
parent
909f801742
commit
c111b239f7
38 changed files with 2242 additions and 37 deletions
23
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/LICENSE
generated
vendored
Normal file
23
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
Copyright (c) 2013, Jérôme Renard
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
4
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/README.md
generated
vendored
Normal file
4
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Syslogparser
|
||||
============
|
||||
|
||||
This is a fork for [github.com/jeromer/syslogparser](https://github.com/jeromer/syslogparser), since this library is intensively used by `go-syslog`, now is integrated as a `internal` package.
|
||||
292
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/rfc3164/rfc3164.go
generated
vendored
Normal file
292
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/rfc3164/rfc3164.go
generated
vendored
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
package rfc3164
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser"
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
buff []byte
|
||||
cursor int
|
||||
l int
|
||||
priority syslogparser.Priority
|
||||
version int
|
||||
header header
|
||||
message rfc3164message
|
||||
location *time.Location
|
||||
skipTag bool
|
||||
}
|
||||
|
||||
type header struct {
|
||||
timestamp time.Time
|
||||
hostname string
|
||||
}
|
||||
|
||||
type rfc3164message struct {
|
||||
tag string
|
||||
content string
|
||||
}
|
||||
|
||||
func NewParser(buff []byte) *Parser {
|
||||
return &Parser{
|
||||
buff: buff,
|
||||
cursor: 0,
|
||||
l: len(buff),
|
||||
location: time.UTC,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) Location(location *time.Location) {
|
||||
p.location = location
|
||||
}
|
||||
|
||||
func (p *Parser) Parse() error {
|
||||
tcursor := p.cursor
|
||||
pri, err := p.parsePriority()
|
||||
if err != nil {
|
||||
// RFC3164 sec 4.3.3
|
||||
p.priority = syslogparser.Priority{13, syslogparser.Facility{Value: 1}, syslogparser.Severity{Value: 5}}
|
||||
p.cursor = tcursor
|
||||
content, err := p.parseContent()
|
||||
p.header.timestamp = time.Now().Round(time.Second)
|
||||
if err != syslogparser.ErrEOL {
|
||||
return err
|
||||
}
|
||||
p.message = rfc3164message{content: content}
|
||||
return nil
|
||||
}
|
||||
|
||||
tcursor = p.cursor
|
||||
hdr, err := p.parseHeader()
|
||||
if err == syslogparser.ErrTimestampUnknownFormat {
|
||||
// RFC3164 sec 4.3.2.
|
||||
hdr.timestamp = time.Now().Round(time.Second)
|
||||
// No tag processing should be done
|
||||
p.skipTag = true
|
||||
// Reset cursor for content read
|
||||
p.cursor = tcursor
|
||||
} else if err != nil {
|
||||
return err
|
||||
} else {
|
||||
p.cursor++
|
||||
}
|
||||
|
||||
msg, err := p.parsemessage()
|
||||
if err != syslogparser.ErrEOL {
|
||||
return err
|
||||
}
|
||||
|
||||
p.priority = pri
|
||||
p.version = syslogparser.NO_VERSION
|
||||
p.header = hdr
|
||||
p.message = msg
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) Dump() syslogparser.LogParts {
|
||||
return syslogparser.LogParts{
|
||||
"timestamp": p.header.timestamp,
|
||||
"hostname": p.header.hostname,
|
||||
"tag": p.message.tag,
|
||||
"content": p.message.content,
|
||||
"priority": p.priority.P,
|
||||
"facility": p.priority.F.Value,
|
||||
"severity": p.priority.S.Value,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) parsePriority() (syslogparser.Priority, error) {
|
||||
return syslogparser.ParsePriority(p.buff, &p.cursor, p.l)
|
||||
}
|
||||
|
||||
func (p *Parser) parseHeader() (header, error) {
|
||||
hdr := header{}
|
||||
var err error
|
||||
|
||||
ts, err := p.parseTimestamp()
|
||||
if err != nil {
|
||||
return hdr, err
|
||||
}
|
||||
|
||||
hostname, err := p.parseHostname()
|
||||
if err != nil {
|
||||
return hdr, err
|
||||
}
|
||||
|
||||
hdr.timestamp = ts
|
||||
hdr.hostname = hostname
|
||||
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parsemessage() (rfc3164message, error) {
|
||||
msg := rfc3164message{}
|
||||
var err error
|
||||
|
||||
if !p.skipTag {
|
||||
tag, err := p.parseTag()
|
||||
if err != nil {
|
||||
return msg, err
|
||||
}
|
||||
msg.tag = tag
|
||||
}
|
||||
|
||||
content, err := p.parseContent()
|
||||
if err != syslogparser.ErrEOL {
|
||||
return msg, err
|
||||
}
|
||||
|
||||
msg.content = content
|
||||
|
||||
return msg, err
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc3164#section-4.1.2
|
||||
func (p *Parser) parseTimestamp() (time.Time, error) {
|
||||
var ts time.Time
|
||||
var err error
|
||||
var tsFmtLen int
|
||||
var sub []byte
|
||||
|
||||
tsFmts := []string{
|
||||
time.Stamp,
|
||||
time.RFC3339,
|
||||
}
|
||||
// if timestamps starts with numeric try formats with different order
|
||||
// it is more likely that timestamp is in RFC3339 format then
|
||||
if c := p.buff[p.cursor]; c > '0' && c < '9' {
|
||||
tsFmts = []string{
|
||||
time.RFC3339,
|
||||
time.Stamp,
|
||||
}
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, tsFmt := range tsFmts {
|
||||
tsFmtLen = len(tsFmt)
|
||||
|
||||
if p.cursor+tsFmtLen > p.l {
|
||||
continue
|
||||
}
|
||||
|
||||
sub = p.buff[p.cursor : tsFmtLen+p.cursor]
|
||||
ts, err = time.ParseInLocation(tsFmt, string(sub), p.location)
|
||||
if err == nil {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
p.cursor = len(time.Stamp)
|
||||
|
||||
// XXX : If the timestamp is invalid we try to push the cursor one byte
|
||||
// XXX : further, in case it is a space
|
||||
if (p.cursor < p.l) && (p.buff[p.cursor] == ' ') {
|
||||
p.cursor++
|
||||
}
|
||||
|
||||
return ts, syslogparser.ErrTimestampUnknownFormat
|
||||
}
|
||||
|
||||
fixTimestampIfNeeded(&ts)
|
||||
|
||||
p.cursor += tsFmtLen
|
||||
|
||||
if (p.cursor < p.l) && (p.buff[p.cursor] == ' ') {
|
||||
p.cursor++
|
||||
}
|
||||
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseHostname() (string, error) {
|
||||
oldcursor := p.cursor
|
||||
hostname, err := syslogparser.ParseHostname(p.buff, &p.cursor, p.l)
|
||||
if err == nil && len(hostname) > 0 && string(hostname[len(hostname)-1]) == ":" { // not an hostname! we found a GNU implementation of syslog()
|
||||
p.cursor = oldcursor - 1
|
||||
myhostname, err := os.Hostname()
|
||||
if err == nil {
|
||||
return myhostname, nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
return hostname, err
|
||||
}
|
||||
|
||||
// http://tools.ietf.org/html/rfc3164#section-4.1.3
|
||||
func (p *Parser) parseTag() (string, error) {
|
||||
var b byte
|
||||
var endOfTag bool
|
||||
var bracketOpen bool
|
||||
var tag []byte
|
||||
var err error
|
||||
var found bool
|
||||
|
||||
from := p.cursor
|
||||
|
||||
for {
|
||||
if p.cursor == p.l {
|
||||
// no tag found, reset cursor for content
|
||||
p.cursor = from
|
||||
return "", nil
|
||||
}
|
||||
|
||||
b = p.buff[p.cursor]
|
||||
bracketOpen = (b == '[')
|
||||
endOfTag = (b == ':' || b == ' ')
|
||||
|
||||
// XXX : parse PID ?
|
||||
if bracketOpen {
|
||||
tag = p.buff[from:p.cursor]
|
||||
found = true
|
||||
}
|
||||
|
||||
if endOfTag {
|
||||
if !found {
|
||||
tag = p.buff[from:p.cursor]
|
||||
found = true
|
||||
}
|
||||
|
||||
p.cursor++
|
||||
break
|
||||
}
|
||||
|
||||
p.cursor++
|
||||
}
|
||||
|
||||
if (p.cursor < p.l) && (p.buff[p.cursor] == ' ') {
|
||||
p.cursor++
|
||||
}
|
||||
|
||||
return string(tag), err
|
||||
}
|
||||
|
||||
func (p *Parser) parseContent() (string, error) {
|
||||
if p.cursor > p.l {
|
||||
return "", syslogparser.ErrEOL
|
||||
}
|
||||
|
||||
content := bytes.Trim(p.buff[p.cursor:p.l], " ")
|
||||
p.cursor += len(content)
|
||||
|
||||
return string(content), syslogparser.ErrEOL
|
||||
}
|
||||
|
||||
func fixTimestampIfNeeded(ts *time.Time) {
|
||||
now := time.Now()
|
||||
y := ts.Year()
|
||||
|
||||
if ts.Year() == 0 {
|
||||
y = now.Year()
|
||||
}
|
||||
|
||||
newTs := time.Date(y, ts.Month(), ts.Day(), ts.Hour(), ts.Minute(),
|
||||
ts.Second(), ts.Nanosecond(), ts.Location())
|
||||
|
||||
*ts = newTs
|
||||
}
|
||||
606
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/rfc5424/rfc5424.go
generated
vendored
Normal file
606
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/rfc5424/rfc5424.go
generated
vendored
Normal file
|
|
@ -0,0 +1,606 @@
|
|||
// Note to self : never try to code while looking after your kids
|
||||
// The result might look like this : https://pbs.twimg.com/media/BXqSuYXIEAAscVA.png
|
||||
|
||||
package rfc5424
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser"
|
||||
)
|
||||
|
||||
const (
|
||||
NILVALUE = '-'
|
||||
)
|
||||
|
||||
var (
|
||||
ErrYearInvalid = &syslogparser.ParserError{"Invalid year in timestamp"}
|
||||
ErrMonthInvalid = &syslogparser.ParserError{"Invalid month in timestamp"}
|
||||
ErrDayInvalid = &syslogparser.ParserError{"Invalid day in timestamp"}
|
||||
ErrHourInvalid = &syslogparser.ParserError{"Invalid hour in timestamp"}
|
||||
ErrMinuteInvalid = &syslogparser.ParserError{"Invalid minute in timestamp"}
|
||||
ErrSecondInvalid = &syslogparser.ParserError{"Invalid second in timestamp"}
|
||||
ErrSecFracInvalid = &syslogparser.ParserError{"Invalid fraction of second in timestamp"}
|
||||
ErrTimeZoneInvalid = &syslogparser.ParserError{"Invalid time zone in timestamp"}
|
||||
ErrInvalidTimeFormat = &syslogparser.ParserError{"Invalid time format"}
|
||||
ErrInvalidAppName = &syslogparser.ParserError{"Invalid app name"}
|
||||
ErrInvalidProcId = &syslogparser.ParserError{"Invalid proc ID"}
|
||||
ErrInvalidMsgId = &syslogparser.ParserError{"Invalid msg ID"}
|
||||
ErrNoStructuredData = &syslogparser.ParserError{"No structured data"}
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
buff []byte
|
||||
cursor int
|
||||
l int
|
||||
header header
|
||||
structuredData string
|
||||
message string
|
||||
}
|
||||
|
||||
type header struct {
|
||||
priority syslogparser.Priority
|
||||
version int
|
||||
timestamp time.Time
|
||||
hostname string
|
||||
appName string
|
||||
procId string
|
||||
msgId string
|
||||
}
|
||||
|
||||
type partialTime struct {
|
||||
hour int
|
||||
minute int
|
||||
seconds int
|
||||
secFrac float64
|
||||
}
|
||||
|
||||
type fullTime struct {
|
||||
pt partialTime
|
||||
loc *time.Location
|
||||
}
|
||||
|
||||
type fullDate struct {
|
||||
year int
|
||||
month int
|
||||
day int
|
||||
}
|
||||
|
||||
func NewParser(buff []byte) *Parser {
|
||||
return &Parser{
|
||||
buff: buff,
|
||||
cursor: 0,
|
||||
l: len(buff),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) Location(location *time.Location) {
|
||||
// Ignore as RFC5424 syslog always has a timezone
|
||||
}
|
||||
|
||||
func (p *Parser) Parse() error {
|
||||
hdr, err := p.parseHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.header = hdr
|
||||
|
||||
sd, err := p.parseStructuredData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.structuredData = sd
|
||||
p.cursor++
|
||||
|
||||
if p.cursor < p.l {
|
||||
p.message = string(p.buff[p.cursor:])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) Dump() syslogparser.LogParts {
|
||||
return syslogparser.LogParts{
|
||||
"priority": p.header.priority.P,
|
||||
"facility": p.header.priority.F.Value,
|
||||
"severity": p.header.priority.S.Value,
|
||||
"version": p.header.version,
|
||||
"timestamp": p.header.timestamp,
|
||||
"hostname": p.header.hostname,
|
||||
"app_name": p.header.appName,
|
||||
"proc_id": p.header.procId,
|
||||
"msg_id": p.header.msgId,
|
||||
"structured_data": p.structuredData,
|
||||
"message": p.message,
|
||||
}
|
||||
}
|
||||
|
||||
// HEADER = PRI VERSION SP TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID
|
||||
func (p *Parser) parseHeader() (header, error) {
|
||||
hdr := header{}
|
||||
|
||||
pri, err := p.parsePriority()
|
||||
if err != nil {
|
||||
return hdr, err
|
||||
}
|
||||
|
||||
hdr.priority = pri
|
||||
|
||||
ver, err := p.parseVersion()
|
||||
if err != nil {
|
||||
return hdr, err
|
||||
}
|
||||
hdr.version = ver
|
||||
p.cursor++
|
||||
|
||||
ts, err := p.parseTimestamp()
|
||||
if err != nil {
|
||||
return hdr, err
|
||||
}
|
||||
|
||||
hdr.timestamp = ts
|
||||
p.cursor++
|
||||
|
||||
host, err := p.parseHostname()
|
||||
if err != nil {
|
||||
return hdr, err
|
||||
}
|
||||
|
||||
hdr.hostname = host
|
||||
p.cursor++
|
||||
|
||||
appName, err := p.parseAppName()
|
||||
if err != nil {
|
||||
return hdr, err
|
||||
}
|
||||
|
||||
hdr.appName = appName
|
||||
p.cursor++
|
||||
|
||||
procId, err := p.parseProcId()
|
||||
if err != nil {
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
hdr.procId = procId
|
||||
p.cursor++
|
||||
|
||||
msgId, err := p.parseMsgId()
|
||||
if err != nil {
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
hdr.msgId = msgId
|
||||
p.cursor++
|
||||
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parsePriority() (syslogparser.Priority, error) {
|
||||
return syslogparser.ParsePriority(p.buff, &p.cursor, p.l)
|
||||
}
|
||||
|
||||
func (p *Parser) parseVersion() (int, error) {
|
||||
return syslogparser.ParseVersion(p.buff, &p.cursor, p.l)
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc5424#section-6.2.3
|
||||
func (p *Parser) parseTimestamp() (time.Time, error) {
|
||||
var ts time.Time
|
||||
|
||||
if p.cursor >= p.l {
|
||||
return ts, ErrInvalidTimeFormat
|
||||
}
|
||||
|
||||
if p.buff[p.cursor] == NILVALUE {
|
||||
p.cursor++
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
fd, err := parseFullDate(p.buff, &p.cursor, p.l)
|
||||
if err != nil {
|
||||
return ts, err
|
||||
}
|
||||
|
||||
if p.cursor >= p.l || p.buff[p.cursor] != 'T' {
|
||||
return ts, ErrInvalidTimeFormat
|
||||
}
|
||||
|
||||
p.cursor++
|
||||
|
||||
ft, err := parseFullTime(p.buff, &p.cursor, p.l)
|
||||
if err != nil {
|
||||
return ts, syslogparser.ErrTimestampUnknownFormat
|
||||
}
|
||||
|
||||
nSec, err := toNSec(ft.pt.secFrac)
|
||||
if err != nil {
|
||||
return ts, err
|
||||
}
|
||||
|
||||
ts = time.Date(
|
||||
fd.year,
|
||||
time.Month(fd.month),
|
||||
fd.day,
|
||||
ft.pt.hour,
|
||||
ft.pt.minute,
|
||||
ft.pt.seconds,
|
||||
nSec,
|
||||
ft.loc,
|
||||
)
|
||||
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// HOSTNAME = NILVALUE / 1*255PRINTUSASCII
|
||||
func (p *Parser) parseHostname() (string, error) {
|
||||
return syslogparser.ParseHostname(p.buff, &p.cursor, p.l)
|
||||
}
|
||||
|
||||
// APP-NAME = NILVALUE / 1*48PRINTUSASCII
|
||||
func (p *Parser) parseAppName() (string, error) {
|
||||
return parseUpToLen(p.buff, &p.cursor, p.l, 48, ErrInvalidAppName)
|
||||
}
|
||||
|
||||
// PROCID = NILVALUE / 1*128PRINTUSASCII
|
||||
func (p *Parser) parseProcId() (string, error) {
|
||||
return parseUpToLen(p.buff, &p.cursor, p.l, 128, ErrInvalidProcId)
|
||||
}
|
||||
|
||||
// MSGID = NILVALUE / 1*32PRINTUSASCII
|
||||
func (p *Parser) parseMsgId() (string, error) {
|
||||
return parseUpToLen(p.buff, &p.cursor, p.l, 32, ErrInvalidMsgId)
|
||||
}
|
||||
|
||||
func (p *Parser) parseStructuredData() (string, error) {
|
||||
return parseStructuredData(p.buff, &p.cursor, p.l)
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
// https://tools.ietf.org/html/rfc5424#section-6
|
||||
// ----------------------------------------------
|
||||
|
||||
// XXX : bind them to Parser ?
|
||||
|
||||
// FULL-DATE : DATE-FULLYEAR "-" DATE-MONTH "-" DATE-MDAY
|
||||
func parseFullDate(buff []byte, cursor *int, l int) (fullDate, error) {
|
||||
var fd fullDate
|
||||
|
||||
year, err := parseYear(buff, cursor, l)
|
||||
if err != nil {
|
||||
return fd, err
|
||||
}
|
||||
|
||||
if *cursor >= l || buff[*cursor] != '-' {
|
||||
return fd, syslogparser.ErrTimestampUnknownFormat
|
||||
}
|
||||
|
||||
*cursor++
|
||||
|
||||
month, err := parseMonth(buff, cursor, l)
|
||||
if err != nil {
|
||||
return fd, err
|
||||
}
|
||||
|
||||
if *cursor >= l || buff[*cursor] != '-' {
|
||||
return fd, syslogparser.ErrTimestampUnknownFormat
|
||||
}
|
||||
|
||||
*cursor++
|
||||
|
||||
day, err := parseDay(buff, cursor, l)
|
||||
if err != nil {
|
||||
return fd, err
|
||||
}
|
||||
|
||||
fd = fullDate{
|
||||
year: year,
|
||||
month: month,
|
||||
day: day,
|
||||
}
|
||||
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// DATE-FULLYEAR = 4DIGIT
|
||||
func parseYear(buff []byte, cursor *int, l int) (int, error) {
|
||||
yearLen := 4
|
||||
|
||||
if *cursor+yearLen > l {
|
||||
return 0, syslogparser.ErrEOL
|
||||
}
|
||||
|
||||
// XXX : we do not check for a valid year (ie. 1999, 2013 etc)
|
||||
// XXX : we only checks the format is correct
|
||||
sub := string(buff[*cursor : *cursor+yearLen])
|
||||
|
||||
*cursor += yearLen
|
||||
|
||||
year, err := strconv.Atoi(sub)
|
||||
if err != nil {
|
||||
return 0, ErrYearInvalid
|
||||
}
|
||||
|
||||
return year, nil
|
||||
}
|
||||
|
||||
// DATE-MONTH = 2DIGIT ; 01-12
|
||||
func parseMonth(buff []byte, cursor *int, l int) (int, error) {
|
||||
return syslogparser.Parse2Digits(buff, cursor, l, 1, 12, ErrMonthInvalid)
|
||||
}
|
||||
|
||||
// DATE-MDAY = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
|
||||
func parseDay(buff []byte, cursor *int, l int) (int, error) {
|
||||
// XXX : this is a relaxed constraint
|
||||
// XXX : we do not check if valid regarding February or leap years
|
||||
// XXX : we only checks that day is in range [01 -> 31]
|
||||
// XXX : in other words this function will not rant if you provide Feb 31th
|
||||
return syslogparser.Parse2Digits(buff, cursor, l, 1, 31, ErrDayInvalid)
|
||||
}
|
||||
|
||||
// FULL-TIME = PARTIAL-TIME TIME-OFFSET
|
||||
func parseFullTime(buff []byte, cursor *int, l int) (fullTime, error) {
|
||||
var loc = new(time.Location)
|
||||
var ft fullTime
|
||||
|
||||
pt, err := parsePartialTime(buff, cursor, l)
|
||||
if err != nil {
|
||||
return ft, err
|
||||
}
|
||||
|
||||
loc, err = parseTimeOffset(buff, cursor, l)
|
||||
if err != nil {
|
||||
return ft, err
|
||||
}
|
||||
|
||||
ft = fullTime{
|
||||
pt: pt,
|
||||
loc: loc,
|
||||
}
|
||||
|
||||
return ft, nil
|
||||
}
|
||||
|
||||
// PARTIAL-TIME = TIME-HOUR ":" TIME-MINUTE ":" TIME-SECOND[TIME-SECFRAC]
|
||||
func parsePartialTime(buff []byte, cursor *int, l int) (partialTime, error) {
|
||||
var pt partialTime
|
||||
|
||||
hour, minute, err := getHourMinute(buff, cursor, l)
|
||||
if err != nil {
|
||||
return pt, err
|
||||
}
|
||||
|
||||
if *cursor >= l || buff[*cursor] != ':' {
|
||||
return pt, ErrInvalidTimeFormat
|
||||
}
|
||||
|
||||
*cursor++
|
||||
|
||||
// ----
|
||||
|
||||
seconds, err := parseSecond(buff, cursor, l)
|
||||
if err != nil {
|
||||
return pt, err
|
||||
}
|
||||
|
||||
pt = partialTime{
|
||||
hour: hour,
|
||||
minute: minute,
|
||||
seconds: seconds,
|
||||
}
|
||||
|
||||
// ----
|
||||
|
||||
if *cursor >= l || buff[*cursor] != '.' {
|
||||
return pt, nil
|
||||
}
|
||||
|
||||
*cursor++
|
||||
|
||||
secFrac, err := parseSecFrac(buff, cursor, l)
|
||||
if err != nil {
|
||||
return pt, nil
|
||||
}
|
||||
pt.secFrac = secFrac
|
||||
|
||||
return pt, nil
|
||||
}
|
||||
|
||||
// TIME-HOUR = 2DIGIT ; 00-23
|
||||
func parseHour(buff []byte, cursor *int, l int) (int, error) {
|
||||
return syslogparser.Parse2Digits(buff, cursor, l, 0, 23, ErrHourInvalid)
|
||||
}
|
||||
|
||||
// TIME-MINUTE = 2DIGIT ; 00-59
|
||||
func parseMinute(buff []byte, cursor *int, l int) (int, error) {
|
||||
return syslogparser.Parse2Digits(buff, cursor, l, 0, 59, ErrMinuteInvalid)
|
||||
}
|
||||
|
||||
// TIME-SECOND = 2DIGIT ; 00-59
|
||||
func parseSecond(buff []byte, cursor *int, l int) (int, error) {
|
||||
return syslogparser.Parse2Digits(buff, cursor, l, 0, 59, ErrSecondInvalid)
|
||||
}
|
||||
|
||||
// TIME-SECFRAC = "." 1*6DIGIT
|
||||
func parseSecFrac(buff []byte, cursor *int, l int) (float64, error) {
|
||||
maxDigitLen := 6
|
||||
|
||||
max := *cursor + maxDigitLen
|
||||
from := *cursor
|
||||
to := from
|
||||
|
||||
for to = from; to < max; to++ {
|
||||
if to >= l {
|
||||
break
|
||||
}
|
||||
|
||||
c := buff[to]
|
||||
if !syslogparser.IsDigit(c) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
sub := string(buff[from:to])
|
||||
if len(sub) == 0 {
|
||||
return 0, ErrSecFracInvalid
|
||||
}
|
||||
|
||||
secFrac, err := strconv.ParseFloat("0."+sub, 64)
|
||||
*cursor = to
|
||||
if err != nil {
|
||||
return 0, ErrSecFracInvalid
|
||||
}
|
||||
|
||||
return secFrac, nil
|
||||
}
|
||||
|
||||
// TIME-OFFSET = "Z" / TIME-NUMOFFSET
|
||||
func parseTimeOffset(buff []byte, cursor *int, l int) (*time.Location, error) {
|
||||
|
||||
if *cursor >= l || buff[*cursor] == 'Z' {
|
||||
*cursor++
|
||||
return time.UTC, nil
|
||||
}
|
||||
|
||||
return parseNumericalTimeOffset(buff, cursor, l)
|
||||
}
|
||||
|
||||
// TIME-NUMOFFSET = ("+" / "-") TIME-HOUR ":" TIME-MINUTE
|
||||
func parseNumericalTimeOffset(buff []byte, cursor *int, l int) (*time.Location, error) {
|
||||
var loc = new(time.Location)
|
||||
|
||||
sign := buff[*cursor]
|
||||
|
||||
if (sign != '+') && (sign != '-') {
|
||||
return loc, ErrTimeZoneInvalid
|
||||
}
|
||||
|
||||
*cursor++
|
||||
|
||||
hour, minute, err := getHourMinute(buff, cursor, l)
|
||||
if err != nil {
|
||||
return loc, err
|
||||
}
|
||||
|
||||
tzStr := fmt.Sprintf("%s%02d:%02d", string(sign), hour, minute)
|
||||
tmpTs, err := time.Parse("-07:00", tzStr)
|
||||
if err != nil {
|
||||
return loc, err
|
||||
}
|
||||
|
||||
return tmpTs.Location(), nil
|
||||
}
|
||||
|
||||
func getHourMinute(buff []byte, cursor *int, l int) (int, int, error) {
|
||||
hour, err := parseHour(buff, cursor, l)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
if *cursor >= l || buff[*cursor] != ':' {
|
||||
return 0, 0, ErrInvalidTimeFormat
|
||||
}
|
||||
|
||||
*cursor++
|
||||
|
||||
minute, err := parseMinute(buff, cursor, l)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return hour, minute, nil
|
||||
}
|
||||
|
||||
func toNSec(sec float64) (int, error) {
|
||||
_, frac := math.Modf(sec)
|
||||
fracStr := strconv.FormatFloat(frac, 'f', 9, 64)
|
||||
fracInt, err := strconv.Atoi(fracStr[2:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return fracInt, nil
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
// https://tools.ietf.org/html/rfc5424#section-6.3
|
||||
// ------------------------------------------------
|
||||
|
||||
func parseStructuredData(buff []byte, cursor *int, l int) (string, error) {
|
||||
var sdData string
|
||||
var found bool
|
||||
|
||||
if *cursor >= l {
|
||||
return "-", nil
|
||||
}
|
||||
|
||||
if buff[*cursor] == NILVALUE {
|
||||
*cursor++
|
||||
return "-", nil
|
||||
}
|
||||
|
||||
if buff[*cursor] != '[' {
|
||||
return sdData, ErrNoStructuredData
|
||||
}
|
||||
|
||||
from := *cursor
|
||||
to := from
|
||||
|
||||
for to = from; to < l; to++ {
|
||||
if found {
|
||||
break
|
||||
}
|
||||
|
||||
b := buff[to]
|
||||
|
||||
if b == ']' {
|
||||
switch t := to + 1; {
|
||||
case t == l:
|
||||
found = true
|
||||
case t <= l && buff[t] == ' ':
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
*cursor = to
|
||||
return string(buff[from:to]), nil
|
||||
}
|
||||
|
||||
return sdData, ErrNoStructuredData
|
||||
}
|
||||
|
||||
func parseUpToLen(buff []byte, cursor *int, l int, maxLen int, e error) (string, error) {
|
||||
var to int
|
||||
var found bool
|
||||
var result string
|
||||
|
||||
max := *cursor + maxLen
|
||||
|
||||
for to = *cursor; (to <= max) && (to < l); to++ {
|
||||
if buff[to] == ' ' {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
result = string(buff[*cursor:to])
|
||||
} else if to > max {
|
||||
to = max // don't go past max
|
||||
}
|
||||
|
||||
*cursor = to
|
||||
|
||||
if found {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
return "", e
|
||||
}
|
||||
213
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/syslogparser.go
generated
vendored
Normal file
213
vendor/gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/syslogparser.go
generated
vendored
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
package syslogparser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
PRI_PART_START = '<'
|
||||
PRI_PART_END = '>'
|
||||
|
||||
NO_VERSION = -1
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEOL = &ParserError{"End of log line"}
|
||||
ErrNoSpace = &ParserError{"No space found"}
|
||||
|
||||
ErrPriorityNoStart = &ParserError{"No start char found for priority"}
|
||||
ErrPriorityEmpty = &ParserError{"Priority field empty"}
|
||||
ErrPriorityNoEnd = &ParserError{"No end char found for priority"}
|
||||
ErrPriorityTooShort = &ParserError{"Priority field too short"}
|
||||
ErrPriorityTooLong = &ParserError{"Priority field too long"}
|
||||
ErrPriorityNonDigit = &ParserError{"Non digit found in priority"}
|
||||
|
||||
ErrVersionNotFound = &ParserError{"Can not find version"}
|
||||
|
||||
ErrTimestampUnknownFormat = &ParserError{"Timestamp format unknown"}
|
||||
|
||||
ErrHostnameTooShort = &ParserError{"Hostname field too short"}
|
||||
)
|
||||
|
||||
type LogParser interface {
|
||||
Parse() error
|
||||
Dump() LogParts
|
||||
Location(*time.Location)
|
||||
}
|
||||
|
||||
type ParserError struct {
|
||||
ErrorString string
|
||||
}
|
||||
|
||||
type Priority struct {
|
||||
P int
|
||||
F Facility
|
||||
S Severity
|
||||
}
|
||||
|
||||
type Facility struct {
|
||||
Value int
|
||||
}
|
||||
|
||||
type Severity struct {
|
||||
Value int
|
||||
}
|
||||
|
||||
type LogParts map[string]interface{}
|
||||
|
||||
// https://tools.ietf.org/html/rfc3164#section-4.1
|
||||
func ParsePriority(buff []byte, cursor *int, l int) (Priority, error) {
|
||||
pri := newPriority(0)
|
||||
|
||||
if l <= 0 {
|
||||
return pri, ErrPriorityEmpty
|
||||
}
|
||||
|
||||
if buff[*cursor] != PRI_PART_START {
|
||||
return pri, ErrPriorityNoStart
|
||||
}
|
||||
|
||||
i := 1
|
||||
priDigit := 0
|
||||
|
||||
for i < l {
|
||||
if i >= 5 {
|
||||
return pri, ErrPriorityTooLong
|
||||
}
|
||||
|
||||
c := buff[i]
|
||||
|
||||
if c == PRI_PART_END {
|
||||
if i == 1 {
|
||||
return pri, ErrPriorityTooShort
|
||||
}
|
||||
|
||||
*cursor = i + 1
|
||||
return newPriority(priDigit), nil
|
||||
}
|
||||
|
||||
if IsDigit(c) {
|
||||
v, e := strconv.Atoi(string(c))
|
||||
if e != nil {
|
||||
return pri, e
|
||||
}
|
||||
|
||||
priDigit = (priDigit * 10) + v
|
||||
} else {
|
||||
return pri, ErrPriorityNonDigit
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
return pri, ErrPriorityNoEnd
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc5424#section-6.2.2
|
||||
func ParseVersion(buff []byte, cursor *int, l int) (int, error) {
|
||||
if *cursor >= l {
|
||||
return NO_VERSION, ErrVersionNotFound
|
||||
}
|
||||
|
||||
c := buff[*cursor]
|
||||
*cursor++
|
||||
|
||||
// XXX : not a version, not an error though as RFC 3164 does not support it
|
||||
if !IsDigit(c) {
|
||||
return NO_VERSION, nil
|
||||
}
|
||||
|
||||
v, e := strconv.Atoi(string(c))
|
||||
if e != nil {
|
||||
*cursor--
|
||||
return NO_VERSION, e
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func IsDigit(c byte) bool {
|
||||
return c >= '0' && c <= '9'
|
||||
}
|
||||
|
||||
func newPriority(p int) Priority {
|
||||
// The Priority value is calculated by first multiplying the Facility
|
||||
// number by 8 and then adding the numerical value of the Severity.
|
||||
|
||||
return Priority{
|
||||
P: p,
|
||||
F: Facility{Value: p / 8},
|
||||
S: Severity{Value: p % 8},
|
||||
}
|
||||
}
|
||||
|
||||
func FindNextSpace(buff []byte, from int, l int) (int, error) {
|
||||
var to int
|
||||
|
||||
for to = from; to < l; to++ {
|
||||
if buff[to] == ' ' {
|
||||
to++
|
||||
return to, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, ErrNoSpace
|
||||
}
|
||||
|
||||
func Parse2Digits(buff []byte, cursor *int, l int, min int, max int, e error) (int, error) {
|
||||
digitLen := 2
|
||||
|
||||
if *cursor+digitLen > l {
|
||||
return 0, ErrEOL
|
||||
}
|
||||
|
||||
sub := string(buff[*cursor : *cursor+digitLen])
|
||||
|
||||
*cursor += digitLen
|
||||
|
||||
i, err := strconv.Atoi(sub)
|
||||
if err != nil {
|
||||
return 0, e
|
||||
}
|
||||
|
||||
if i >= min && i <= max {
|
||||
return i, nil
|
||||
}
|
||||
|
||||
return 0, e
|
||||
}
|
||||
|
||||
func ParseHostname(buff []byte, cursor *int, l int) (string, error) {
|
||||
from := *cursor
|
||||
|
||||
if from >= l {
|
||||
return "", ErrHostnameTooShort
|
||||
}
|
||||
|
||||
var to int
|
||||
|
||||
for to = from; to < l; to++ {
|
||||
if buff[to] == ' ' {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
hostname := buff[from:to]
|
||||
|
||||
*cursor = to
|
||||
|
||||
return string(hostname), nil
|
||||
}
|
||||
|
||||
func ShowCursorPos(buff []byte, cursor int) {
|
||||
fmt.Println(string(buff))
|
||||
padding := strings.Repeat("-", cursor)
|
||||
fmt.Println(padding + "↑\n")
|
||||
}
|
||||
|
||||
func (err *ParserError) Error() string {
|
||||
return err.ErrorString
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue