mirror of
https://codeberg.org/superseriousbusiness/gotosocial.git
synced 2024-12-27 03:18:16 +03:00
214 lines
3.6 KiB
Go
214 lines
3.6 KiB
Go
|
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
|
||
|
}
|