Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: allow passing down machine options from nontransparent/octetcounting parsers #23

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
2 changes: 1 addition & 1 deletion common/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package common
import "strings"

// UnsafeUTF8DecimalCodePointsToInt converts a slice containing
// a series of UTF-8 decimal code points into their integer rapresentation.
// a series of UTF-8 decimal code points into their integer representation.
//
// It assumes input code points are in the range 48-57.
// Returns a pointer since an empty slice is equal to nil and not to the zero value of the codomain (ie., `int`).
Expand Down
56 changes: 51 additions & 5 deletions nontransparent/example_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package nontransparent

import (
"github.com/davecgh/go-spew/spew"
"io"
"math/rand"
"strings"
"time"

"github.com/davecgh/go-spew/spew"
"github.com/leodido/go-syslog/v4"
"time"
"github.com/leodido/go-syslog/v4/rfc3164"
"github.com/leodido/go-syslog/v4/rfc5424"
)

func Example_withoutTrailerAtEnd() {
Expand All @@ -28,14 +30,58 @@ func Example_withoutTrailerAtEnd() {
// }
}

func Example_withCurrentYear_RFC3164() {
results := []syslog.Result{}
acc := func(res *syslog.Result) {
if res != nil {
// Force year to match the one in the comment below
x, _ := res.Message.(*rfc3164.SyslogMessage)
x.Timestamp = func(t1 *time.Time) *time.Time {
currentY := time.Now().Year()
t2 := t1.AddDate(2021-currentY, 0, 0)

return &t2
}(x.Timestamp)
newRes := syslog.Result{Message: x, Error: res.Error}
results = append(results, newRes)
}
}
// Notice the message ends without trailer but we catch it anyway
r := strings.NewReader("<13>Dec 2 16:31:03 host app: Test\n")
NewParserRFC3164(
syslog.WithListener(acc),
syslog.WithMachineOptions(rfc3164.WithYear(rfc3164.CurrentYear{})),
).Parse(r)
output(results)
// Output:
// ([]syslog.Result) (len=1) {
// (syslog.Result) {
// Message: (*rfc3164.SyslogMessage)({
// Base: (syslog.Base) {
// Facility: (*uint8)(1),
// Severity: (*uint8)(5),
// Priority: (*uint8)(13),
// Timestamp: (*time.Time)(2021-12-02 16:31:03 +0000 UTC),
// Hostname: (*string)((len=4) "host"),
// Appname: (*string)((len=3) "app"),
// ProcID: (*string)(<nil>),
// MsgID: (*string)(<nil>),
// Message: (*string)((len=4) "Test")
// }
// }),
// Error: (error) <nil>
// }
// }
}

func Example_bestEffortWithoutTrailerAtEnd() {
results := []syslog.Result{}
acc := func(res *syslog.Result) {
results = append(results, *res)
}
// Notice the message ends without trailer but we catch it anyway
r := strings.NewReader("<1>1 2003-10-11T22:14:15.003Z host.local - - - - mex")
NewParser(syslog.WithBestEffort(), syslog.WithListener(acc)).Parse(r)
NewParser(syslog.WithMachineOptions(rfc5424.WithBestEffort()), syslog.WithListener(acc)).Parse(r)
output(results)
// Output:
// ([]syslog.Result) (len=1) {
Expand Down Expand Up @@ -66,7 +112,7 @@ func Example_bestEffortOnLastOne() {
results = append(results, *res)
}
r := strings.NewReader("<1>1 - - - - - - -\n<3>1\n")
NewParser(syslog.WithBestEffort(), syslog.WithListener(acc)).Parse(r)
NewParser(syslog.WithMachineOptions(rfc5424.WithBestEffort()), syslog.WithListener(acc)).Parse(r)
output(results)
// Output:
// ([]syslog.Result) (len=2) {
Expand Down Expand Up @@ -137,7 +183,7 @@ func Example_intoChannelWithLF() {
results <- x
}

p := NewParser(syslog.WithListener(ln), syslog.WithBestEffort())
p := NewParser(syslog.WithListener(ln), syslog.WithMachineOptions(rfc5424.WithBestEffort()))
go func() {
defer close(results)
defer r.Close()
Expand Down
43 changes: 14 additions & 29 deletions nontransparent/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ const nontransparentError int = 0
const nontransparentEnMain int = 1

type machine struct {
trailertyp TrailerType // default is 0 thus TrailerType(LF)
trailer byte
candidate []byte
bestEffort bool
internal syslog.Machine
emit syslog.ParserListener
readError error
lastChunk []byte // store last candidate message also if it does not ends with a trailer
trailertyp TrailerType // default is 0 thus TrailerType(LF)
trailer byte
candidate []byte
internal syslog.Machine
internalOpts []syslog.MachineOption
emit syslog.ParserListener
readError error
lastChunk []byte // store last candidate message also if it does not ends with a trailer
}

// Exec implements the ragel.Parser interface.
Expand Down Expand Up @@ -183,7 +183,7 @@ func (m *machine) OnCompletion() {
// Try to parse last chunk as a candidate
if m.readError != nil && len(m.lastChunk) > 0 {
res, err := m.internal.Parse(m.lastChunk)
if err == nil && !m.bestEffort {
if err == nil && !m.internal.HasBestEffort() {
res = nil
err = m.readError
}
Expand All @@ -209,11 +209,7 @@ func NewParser(options ...syslog.ParserOption) syslog.Parser {
m.trailer = byte(trailer)

// Create internal parser depending on options
if m.bestEffort {
m.internal = rfc5424.NewMachine(rfc5424.WithBestEffort())
} else {
m.internal = rfc5424.NewMachine()
}
m.internal = rfc5424.NewMachine(m.internalOpts...)

return m
}
Expand All @@ -232,23 +228,14 @@ func NewParserRFC3164(options ...syslog.ParserOption) syslog.Parser {
m.trailer = byte(trailer)

// Create internal parser depending on options
if m.bestEffort {
m.internal = rfc3164.NewMachine(rfc3164.WithBestEffort())
} else {
m.internal = rfc3164.NewMachine()
}
m.internal = rfc3164.NewMachine(m.internalOpts...)

return m
}

// WithMaxMessageLength does nothing for this parser.
func (m *machine) WithMaxMessageLength(length int) {}

// HasBestEffort tells whether the receiving parser has best effort mode on or off.
func (m *machine) HasBestEffort() bool {
return m.bestEffort
}

// WithTrailer ... todo(leodido)
func WithTrailer(t TrailerType) syslog.ParserOption {
return func(m syslog.Parser) syslog.Parser {
Expand All @@ -260,11 +247,9 @@ func WithTrailer(t TrailerType) syslog.ParserOption {
}
}

// WithBestEffort implements the syslog.BestEfforter interface.
//
// The generic options uses it.
func (m *machine) WithBestEffort() {
m.bestEffort = true
// WithMachineOptions configures options for the underlying parsing machine.
func (m *machine) WithMachineOptions(opts ...syslog.MachineOption) {
m.internalOpts = append(m.internalOpts, opts...)
}

// WithListener implements the syslog.Parser interface.
Expand Down
43 changes: 14 additions & 29 deletions nontransparent/parser.go.rl
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ main :=
%% write data nofinal;

type machine struct{
trailertyp TrailerType // default is 0 thus TrailerType(LF)
trailer byte
candidate []byte
bestEffort bool
internal syslog.Machine
emit syslog.ParserListener
readError error
lastChunk []byte // store last candidate message also if it does not ends with a trailer
trailertyp TrailerType // default is 0 thus TrailerType(LF)
trailer byte
candidate []byte
internal syslog.Machine
internalOpts []syslog.MachineOption
emit syslog.ParserListener
readError error
lastChunk []byte // store last candidate message also if it does not ends with a trailer
}

// Exec implements the ragel.Parser interface.
Expand Down Expand Up @@ -79,7 +79,7 @@ func (m *machine) OnCompletion() {
// Try to parse last chunk as a candidate
if m.readError != nil && len(m.lastChunk) > 0 {
res, err := m.internal.Parse(m.lastChunk)
if err == nil && !m.bestEffort {
if err == nil && !m.internal.HasBestEffort() {
res = nil
err = m.readError
}
Expand All @@ -105,11 +105,7 @@ func NewParser(options ...syslog.ParserOption) syslog.Parser {
m.trailer = byte(trailer)

// Create internal parser depending on options
if m.bestEffort {
m.internal = rfc5424.NewMachine(rfc5424.WithBestEffort())
} else {
m.internal = rfc5424.NewMachine()
}
m.internal = rfc5424.NewMachine(m.internalOpts...)

return m
}
Expand All @@ -128,23 +124,14 @@ func NewParserRFC3164(options ...syslog.ParserOption) syslog.Parser {
m.trailer = byte(trailer)

// Create internal parser depending on options
if m.bestEffort {
m.internal = rfc3164.NewMachine(rfc3164.WithBestEffort())
} else {
m.internal = rfc3164.NewMachine()
}
m.internal = rfc3164.NewMachine(m.internalOpts...)

return m
}

// WithMaxMessageLength does nothing for this parser.
func (m *machine) WithMaxMessageLength(length int) {}

// HasBestEffort tells whether the receiving parser has best effort mode on or off.
func (m *machine) HasBestEffort() bool {
return m.bestEffort
}

// WithTrailer ... todo(leodido)
func WithTrailer(t TrailerType) syslog.ParserOption {
return func(m syslog.Parser) syslog.Parser {
Expand All @@ -156,11 +143,9 @@ func WithTrailer(t TrailerType) syslog.ParserOption {
}
}

// WithBestEffort implements the syslog.BestEfforter interface.
//
// The generic options uses it.
func (m *machine) WithBestEffort() {
m.bestEffort = true
// WithMachineOptions configures options for the underlying parsing machine.
func (m *machine) WithMachineOptions(opts ...syslog.MachineOption) {
m.internalOpts = append(m.internalOpts, opts...)
}

// WithListener implements the syslog.Parser interface.
Expand Down
46 changes: 19 additions & 27 deletions nontransparent/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import (
)

type testCase struct {
descr string
input string
substitute bool
results []syslog.Result
pResults []syslog.Result
descr string
input string
substitute bool
results []syslog.Result
effortResults []syslog.Result
}

var testCases []testCase
Expand All @@ -28,14 +28,15 @@ func getParsingError(col int) error {

func getTestCases() []testCase {
return []testCase{
// fixme(leodido)
// {
// "empty",
// "",
// []syslog.Result{},
// []syslog.Result{},
// },

// note > no error nor message (nil) returned
// TODO: should this return an EOF error or ...?
{
"empty",
"",
false,
[]syslog.Result{},
[]syslog.Result{},
},
{
"1st ok",
"<1>1 - - - - - -%[1]s",
Expand Down Expand Up @@ -131,8 +132,7 @@ func getTestCases() []testCase {
},
},
},

// todo(leodido)
// TODO: complete the test cases
// {
// "1st ok//incomplete/2nd ok//incomplete",
// "",
Expand Down Expand Up @@ -177,12 +177,12 @@ func TestParse(t *testing.T) {
t.Parallel()

res := []syslog.Result{}
effortParser := NewParser(syslog.WithBestEffort(), syslog.WithListener(func(r *syslog.Result) {
effortParser := NewParser(syslog.WithMachineOptions(rfc5424.WithBestEffort()), syslog.WithListener(func(r *syslog.Result) {
res = append(res, *r)
}))
effortParser.Parse(strings.NewReader(inputWithLF))

assert.Equal(t, tc.pResults, res)
assert.Equal(t, tc.effortResults, res)
})

// Test with trailer NUL
Expand All @@ -206,20 +206,12 @@ func TestParse(t *testing.T) {
t.Parallel()

res := []syslog.Result{}
effortParser := NewParser(syslog.WithBestEffort(), syslog.WithListener(func(r *syslog.Result) {
effortParser := NewParser(syslog.WithMachineOptions(rfc5424.WithBestEffort()), syslog.WithListener(func(r *syslog.Result) {
res = append(res, *r)
}), WithTrailer(NUL))
effortParser.Parse(strings.NewReader(inputWithNUL))

assert.Equal(t, tc.pResults, res)
assert.Equal(t, tc.effortResults, res)
})
}
}

func TestParserBestEffortOption(t *testing.T) {
p1 := NewParser().(syslog.BestEfforter)
assert.False(t, p1.HasBestEffort())

p2 := NewParser(syslog.WithBestEffort()).(syslog.BestEfforter)
assert.True(t, p2.HasBestEffort())
}
Loading
Loading