gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

automatic.go (3322B)


      1 package format
      2 
      3 import (
      4 	"bufio"
      5 	"bytes"
      6 	"strconv"
      7 
      8 	"gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/rfc3164"
      9 	"gopkg.in/mcuadros/go-syslog.v2/internal/syslogparser/rfc5424"
     10 )
     11 
     12 /* Selecting an 'Automatic' format detects incoming format (i.e. RFC3164 vs RFC5424) and Framing
     13  * (i.e. RFC6587 s3.4.1 octet counting as described here as RFC6587, and either no framing or
     14  * RFC6587 s3.4.2 octet stuffing / non-transparent framing, described here as either RFC3164
     15  * or RFC6587).
     16  *
     17  * In essence if you don't know which format to select, or have multiple incoming formats, this
     18  * is the one to go for. There is a theoretical performance penalty (it has to look at a few bytes
     19  * at the start of the frame), and a risk that you may parse things you don't want to parse
     20  * (rogue syslog clients using other formats), so if you can be absolutely sure of your syslog
     21  * format, it would be best to select it explicitly.
     22  */
     23 
     24 type Automatic struct{}
     25 
     26 const (
     27 	detectedUnknown = iota
     28 	detectedRFC3164 = iota
     29 	detectedRFC5424 = iota
     30 	detectedRFC6587 = iota
     31 )
     32 
     33 /*
     34  * Will always fallback to rfc3164 (see section 4.3.3)
     35  */
     36 func detect(data []byte) int {
     37 	// all formats have a sapce somewhere
     38 	if i := bytes.IndexByte(data, ' '); i > 0 {
     39 		pLength := data[0:i]
     40 		if _, err := strconv.Atoi(string(pLength)); err == nil {
     41 			return detectedRFC6587
     42 		}
     43 		// are we starting with <
     44 		if data[0] != '<' {
     45 			return detectedRFC3164
     46 		}
     47 		// is there a close angle bracket before the ' '? there should be
     48 		angle := bytes.IndexByte(data, '>')
     49 		if (angle < 0) || (angle >= i) {
     50 			return detectedRFC3164
     51 		}
     52 
     53 		// if a single digit immediately follows the angle bracket, then a space
     54 		// it is RFC5424, as RFC3164 must begin with a letter (month name)
     55 		if (angle+2 == i) && (data[angle+1] >= '0') && (data[angle+1] <= '9') {
     56 			return detectedRFC5424
     57 		} else {
     58 			return detectedRFC3164
     59 		}
     60 	}
     61 	// fallback to rfc 3164 section 4.3.3
     62 	return detectedRFC3164
     63 }
     64 
     65 func (f *Automatic) GetParser(line []byte) LogParser {
     66 	switch format := detect(line); format {
     67 	case detectedRFC3164:
     68 		return &parserWrapper{rfc3164.NewParser(line)}
     69 	case detectedRFC5424:
     70 		return &parserWrapper{rfc5424.NewParser(line)}
     71 	default:
     72 		// If the line was an RFC6587 line, the splitter should already have removed the length,
     73 		// so one of the above two will be chosen if the line is correctly formed. However, it
     74 		// may have a second length illegally placed at the start, in which case the detector
     75 		// will return detectedRFC6587. The line may also simply be malformed after the length in
     76 		// which case we will have detectedUnknown. In this case we return the simplest parser so
     77 		// the illegally formatted line is properly handled
     78 		return &parserWrapper{rfc3164.NewParser(line)}
     79 	}
     80 }
     81 
     82 func (f *Automatic) GetSplitFunc() bufio.SplitFunc {
     83 	return f.automaticScannerSplit
     84 }
     85 
     86 func (f *Automatic) automaticScannerSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
     87 	if atEOF && len(data) == 0 {
     88 		return 0, nil, nil
     89 	}
     90 
     91 	switch format := detect(data); format {
     92 	case detectedRFC6587:
     93 		return rfc6587ScannerSplit(data, atEOF)
     94 	case detectedRFC3164, detectedRFC5424:
     95 		// the default
     96 		return bufio.ScanLines(data, atEOF)
     97 	default:
     98 		if err != nil {
     99 			return 0, nil, err
    100 		}
    101 		// Request more data
    102 		return 0, nil, nil
    103 	}
    104 }