Commit b0b44cb9 authored by Michael Prokop's avatar Michael Prokop

New upstream version 2.0.0

parents
version: 2
jobs:
test:
docker:
- image: circleci/golang:1.11
environment:
GOCACHE: /tmp/go-cache
GOFLAGS: "-mod=readonly -p=4"
working_directory: "/go/src/github.com/influxdata/go-syslog"
steps:
- checkout
- restore_cache:
name: Restoring caches
keys:
- go-syslog-gocache-{{ .Branch }}-{{ .Revision }}
- go-syslog-modules-{{ checksum "go.sum" }}
- run: make GO_ARGS="-timeout 20s -coverprofile cover.out -race -v" tests
- save_cache:
name: Caching GOCACHE
key: go-syslog-gocache-{{ .Branch }}-{{ .Revision }}
paths:
- /tmp/go-cache
when: always
- save_cache:
name: Caching modules
key: go-syslog-modules-{{ checksum "go.sum" }}
paths:
- /go/pkg/mod
when: always
workflows:
version: 2
testing:
jobs:
- test
\ No newline at end of file
debug.test
docs/*.png
.vscode/
*.out
*.html
\ No newline at end of file
The MIT License
Copyright (c) 2018, InfluxData Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
\ No newline at end of file
[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=for-the-badge)](LICENSE)
**A parser for syslog messages**.
> [Blazing fast](#Performances) RFC5424-compliant parsers
To wrap up, this package provides:
- a RFC5424-compliant parser
- a RFC5424-compliant builder
- a parser which works on streams for syslog with [octet counting](https://tools.ietf.org/html/rfc5425#section-4.3) framing technique
- a parser which works on streams for syslog with [non-transparent](https://tools.ietf.org/html/rfc6587#section-3.4.2) framing technique
This library provides the pieces to parse syslog messages transported following various RFCs.
For example:
- TLS with octet count ([RFC5425](https://tools.ietf.org/html/rfc5425))
- TCP with non-transparent framing or with octet count ([RFC 6587](https://tools.ietf.org/html/rfc6587))
- UDP carrying one message per packet ([RFC5426](https://tools.ietf.org/html/rfc5426))
## Installation
```
go get github.com/influxdata/go-syslog
```
## Docs
[![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge)](http://godoc.org/github.com/influxdata/go-syslog)
The [docs](docs/) directory contains `.dot` files representing the FSM parts of a [RFC5424](https://tools.ietf.org/html/rfc5424) syslog message and also the ones representing the other transport parsers.
## Usage
Suppose you want to parse a given sequence of bytes as a RFC5424 message.
```go
i := []byte(`<165>4 2018-10-11T22:14:15.003Z mymach.it e - 1 [ex@32473 iut="3"] An application event log entry...`)
p := rfc5424.NewParser()
m, e := p.Parse(i, nil)
```
This results in `m` being equal to:
```go
// (*rfc5424.SyslogMessage)({
// priority: (*uint8)(165),
// facility: (*uint8)(20),
// severity: (*uint8)(5),
// version: (uint16) 4,
// timestamp: (*time.Time)(2018-10-11 22:14:15.003 +0000 UTC),
// hostname: (*string)((len=9) "mymach.it"),
// appname: (*string)((len=1) "e"),
// procID: (*string)(<nil>),
// msgID: (*string)((len=1) "1"),
// structuredData: (*map[string]map[string]string)((len=1) {
// (string) (len=8) "ex@32473": (map[string]string) (len=1) {
// (string) (len=3) "iut": (string) (len=1) "3"
// }
// }),
// message: (*string)((len=33) "An application event log entry...")
// })
```
And `e` being equal to `nil`, since the `i` is a perfectly valid RFC5424 message.
### Best effort mode
RFC5424 parser has the ability to perform partial matches (until it can).
With this mode enabled, when the parsing process errors out it returns the message collected until that position, and the error that caused the parser to stop.
Notice that in this modality the output is returned _iff_ it represents a minimally valid message - ie., a message containing almost a priority field in `[1,191]` within angular brackets, followed by a version in `]0,999]`.
Let's look at an example.
```go
bestEffortOn := true
i := []byte("<1>1 A - - - - - -")
p := NewParser()
m, e := p.Parse(i, &bestEffortOn)
```
This results in `m` being equal to the following `SyslogMessage` instance.
```go
// (*rfc5424.SyslogMessage)({
// priority: (*uint8)(1),
// facility: (*uint8)(0),
// severity: (*uint8)(1),
// version: (uint16) 1,
// timestamp: (*time.Time)(<nil>),
// hostname: (*string)(<nil>),
// appname: (*string)(<nil>),
// procID: (*string)(<nil>),
// msgID: (*string)(<nil>),
// structuredData: (*map[string]map[string]string)(<nil>),
// message: (*string)(<nil>)
// })
```
And, at the same time, in `e` reporting the error that actually stopped the parser.
```go
expecting a RFC3339MICRO timestamp or a nil value [col 5]
```
Both `m` and `e` have a value since at the column the parser stopped it already was able to construct a minimally valid `SyslogMessage`.
### Builder
This library also provides a builder to construct valid syslog messages.
Notice that its API ignores input values that does not match the grammar.
Let's have a look to an example.
```go
msg := &SyslogMessage{}
msg.SetTimestamp("not a RFC3339MICRO timestamp")
msg.Valid() // Not yet a valid message (try msg.Valid())
msg.SetPriority(191)
msg.SetVersion(1)
msg.Valid() // Now it is minimally valid
```
Printing `msg` you will verify it contains a `nil` timestamp (since an invalid one has been given).
```go
// (*rfc5424.SyslogMessage)({
// priority: (*uint8)(191),
// facility: (*uint8)(23),
// severity: (*uint8)(7),
// version: (uint16) 1,
// timestamp: (*time.Time)(<nil>),
// hostname: (*string)(<nil>),
// appname: (*string)(<nil>),
// procID: (*string)(<nil>),
// msgID: (*string)(<nil>),
// structuredData: (*map[string]map[string]string)(<nil>),
// message: (*string)(<nil>)
// })
```
Finally you can serialize the message into a string.
```go
str, _ := msg.String()
// <191>1 - - - - - -
```
## Message transfer
Excluding encapsulating one message for packet in packet protocols there are two ways to transfer syslog messages over streams.
The older - ie., the **non-transparent** framing - and the newer one - ie., the **octet counting** framing - which is reliable and has not been seen to cause problems noted with the non-transparent one.
This library provide stream parsers for both.
### Octet counting
In short, [RFC5425](https://tools.ietf.org/html/rfc5425#section-4.3) and [RFC6587](), aside from the protocol considerations, describe a **transparent framing** technique for syslog messages that uses the **octect counting** technique - ie., the message lenght of the incoming message.
Each syslog message is sent with a prefix representing the number of bytes it is made of.
This [package](./octetcounting) parses messages stream following such rule.
To quickly understand how to use it please have a look at the [example file](./octetcounting/example_test.go).
### Non transparent
The [RFC6587](https://tools.ietf.org/html/rfc6587#section-3.4.2) also describes the **non-transparent framing** transport of syslog messages.
In such case the messages are separated by a trailer, usually a line feed.
This [package](./nontransparent) parses message stream following such [technique](https://tools.ietf.org/html/rfc6587#section-3.4.2).
To quickly understand how to use it please have a look at the [example file](./nontransparent/example_test.go).
Things we do not support:
- trailers other than `LF` or `NUL`
- trailer which length is greater than 1 byte
- trailer change on a frame-by-frame basis
## Performances
To run the benchmark execute the following command.
```bash
make bench
```
On my machine<sup>[1](#mymachine)</sup> this are the results obtained in best effort mode.
```
[no]_empty_input__________________________________-4 30000000 253 ns/op 224 B/op 3 allocs/op
[no]_multiple_syslog_messages_on_multiple_lines___-4 20000000 433 ns/op 304 B/op 12 allocs/op
[no]_impossible_timestamp_________________________-4 10000000 1080 ns/op 528 B/op 11 allocs/op
[no]_malformed_structured_data____________________-4 20000000 552 ns/op 400 B/op 12 allocs/op
[no]_with_duplicated_structured_data_id___________-4 5000000 1246 ns/op 688 B/op 17 allocs/op
[ok]_minimal______________________________________-4 30000000 264 ns/op 247 B/op 9 allocs/op
[ok]_average_message______________________________-4 5000000 1984 ns/op 1536 B/op 26 allocs/op
[ok]_complicated_message__________________________-4 5000000 1644 ns/op 1280 B/op 25 allocs/op
[ok]_very_long_message____________________________-4 2000000 3826 ns/op 2464 B/op 28 allocs/op
[ok]_all_max_length_and_complete__________________-4 3000000 2792 ns/op 1888 B/op 28 allocs/op
[ok]_all_max_length_except_structured_data_and_mes-4 5000000 1830 ns/op 883 B/op 13 allocs/op
[ok]_minimal_with_message_containing_newline______-4 20000000 294 ns/op 250 B/op 10 allocs/op
[ok]_w/o_procid,_w/o_structured_data,_with_message-4 10000000 956 ns/op 364 B/op 11 allocs/op
[ok]_minimal_with_UTF-8_message___________________-4 20000000 586 ns/op 359 B/op 10 allocs/op
[ok]_with_structured_data_id,_w/o_structured_data_-4 10000000 998 ns/op 592 B/op 14 allocs/op
[ok]_with_multiple_structured_data________________-4 5000000 1538 ns/op 1232 B/op 22 allocs/op
[ok]_with_escaped_backslash_within_structured_data-4 5000000 1316 ns/op 920 B/op 20 allocs/op
[ok]_with_UTF-8_structured_data_param_value,_with_-4 5000000 1580 ns/op 1050 B/op 21 allocs/op
```
As you can see it takes:
* ~250ns to parse the smallest legal message
* ~2µs to parse an average legal message
* ~4µs to parse a very long legal message
Other RFC5424 implementations, like this [one](https://github.com/roguelazer/rust-syslog-rfc5424) in Rust, spend 8µs to parse an average legal message.
_TBD: comparation against other golang parsers_.
---
* <a name="mymachine">[1]</a>: Intel Core i7-7600U CPU @ 2.80GHz
\ No newline at end of file
digraph nontransparent {
rankdir=LR;
node [ shape = point ];
ENTRY;
en_1;
node [ shape = circle, height = 0.2 ];
node [ fixedsize = true, height = 0.65, shape = doublecircle ];
3;
node [ shape = circle ];
1 -> 2 [ label = "'<' / on_init" ];
2 -> 2 [ label = "1..'\\t', '\\v'..255, '\\n'(!27:13), 0(!27:13)" ];
2 -> 3 [ label = "'\\n'(27:13), 0(28:13) / on_trailer" ];
3 -> 2 [ label = "1..'\\t', '\\v'..';', '='..255, '\\n'(!27:13), 0(!27:13)" ];
3 -> 2 [ label = "'<' / on_init" ];
3 -> 3 [ label = "'\\n'(27:13), 0(28:13) / on_trailer" ];
ENTRY -> 1 [ label = "IN" ];
en_1 -> 1 [ label = "main" ];
}
This source diff could not be displayed because it is too large. You can view the blob instead.
digraph rfc5424 {
rankdir=LR;
node [ shape = point ];
ENTRY;
eof_1;
eof_2;
eof_3;
eof_4;
eof_5;
eof_6;
eof_7;
eof_8;
eof_9;
eof_10;
eof_11;
eof_12;
eof_13;
eof_14;
eof_15;
eof_16;
eof_17;
eof_18;
eof_19;
eof_20;
eof_21;
eof_22;
eof_23;
eof_24;
eof_25;
eof_26;
eof_27;
eof_28;
eof_29;
eof_30;
eof_31;
eof_32;
eof_33;
eof_34;
eof_35;
eof_36;
eof_37;
eof_38;
eof_39;
eof_40;
eof_41;
eof_42;
eof_43;
eof_44;
eof_45;
eof_46;
eof_47;
eof_48;
eof_49;
node [ shape = circle, height = 0.2 ];
err_1 [ label=""];
err_2 [ label=""];
err_3 [ label=""];
err_4 [ label=""];
err_5 [ label=""];
err_6 [ label=""];
err_7 [ label=""];
err_8 [ label=""];
err_9 [ label=""];
err_10 [ label=""];
err_11 [ label=""];
err_12 [ label=""];
err_13 [ label=""];
err_14 [ label=""];
err_15 [ label=""];
err_16 [ label=""];
err_17 [ label=""];
err_18 [ label=""];
err_19 [ label=""];
err_20 [ label=""];
err_21 [ label=""];
err_22 [ label=""];
err_23 [ label=""];
err_24 [ label=""];
err_25 [ label=""];
err_26 [ label=""];
err_27 [ label=""];
err_28 [ label=""];
err_29 [ label=""];
err_30 [ label=""];
err_31 [ label=""];
err_32 [ label=""];
err_33 [ label=""];
err_34 [ label=""];
err_35 [ label=""];
err_36 [ label=""];
err_37 [ label=""];
err_38 [ label=""];
err_39 [ label=""];
err_40 [ label=""];
err_41 [ label=""];
err_42 [ label=""];
err_43 [ label=""];
err_44 [ label=""];
err_45 [ label=""];
err_46 [ label=""];
err_47 [ label=""];
err_48 [ label=""];
err_49 [ label=""];
node [ fixedsize = true, height = 0.65, shape = doublecircle ];
2;
3;
4;
5;
6;
7;
8;
9;
10;
11;
12;
13;
14;
15;
16;
17;
18;
19;
20;
21;
22;
23;
24;
25;
26;
27;
28;
29;
30;
31;
32;
33;
34;
35;
36;
37;
38;
39;
40;
41;
42;
43;
44;
45;
46;
47;
48;
49;
node [ shape = circle ];
1 -> 2 [ label = "'!'..'~' / mark" ];
1 -> err_1 [ label = "DEF / err_appname" ];
2 -> 3 [ label = "'!'..'~'" ];
2 -> err_2 [ label = "DEF / err_appname" ];
3 -> 4 [ label = "'!'..'~'" ];
3 -> err_3 [ label = "DEF / err_appname" ];
4 -> 5 [ label = "'!'..'~'" ];
4 -> err_4 [ label = "DEF / err_appname" ];
5 -> 6 [ label = "'!'..'~'" ];
5 -> err_5 [ label = "DEF / err_appname" ];
6 -> 7 [ label = "'!'..'~'" ];
6 -> err_6 [ label = "DEF / err_appname" ];
7 -> 8 [ label = "'!'..'~'" ];
7 -> err_7 [ label = "DEF / err_appname" ];
8 -> 9 [ label = "'!'..'~'" ];
8 -> err_8 [ label = "DEF / err_appname" ];
9 -> 10 [ label = "'!'..'~'" ];
9 -> err_9 [ label = "DEF / err_appname" ];
10 -> 11 [ label = "'!'..'~'" ];
10 -> err_10 [ label = "DEF / err_appname" ];
11 -> 12 [ label = "'!'..'~'" ];
11 -> err_11 [ label = "DEF / err_appname" ];
12 -> 13 [ label = "'!'..'~'" ];
12 -> err_12 [ label = "DEF / err_appname" ];
13 -> 14 [ label = "'!'..'~'" ];
13 -> err_13 [ label = "DEF / err_appname" ];
14 -> 15 [ label = "'!'..'~'" ];
14 -> err_14 [ label = "DEF / err_appname" ];
15 -> 16 [ label = "'!'..'~'" ];
15 -> err_15 [ label = "DEF / err_appname" ];
16 -> 17 [ label = "'!'..'~'" ];
16 -> err_16 [ label = "DEF / err_appname" ];
17 -> 18 [ label = "'!'..'~'" ];
17 -> err_17 [ label = "DEF / err_appname" ];
18 -> 19 [ label = "'!'..'~'" ];
18 -> err_18 [ label = "DEF / err_appname" ];
19 -> 20 [ label = "'!'..'~'" ];
19 -> err_19 [ label = "DEF / err_appname" ];
20 -> 21 [ label = "'!'..'~'" ];
20 -> err_20 [ label = "DEF / err_appname" ];
21 -> 22 [ label = "'!'..'~'" ];
21 -> err_21 [ label = "DEF / err_appname" ];
22 -> 23 [ label = "'!'..'~'" ];
22 -> err_22 [ label = "DEF / err_appname" ];
23 -> 24 [ label = "'!'..'~'" ];
23 -> err_23 [ label = "DEF / err_appname" ];
24 -> 25 [ label = "'!'..'~'" ];
24 -> err_24 [ label = "DEF / err_appname" ];
25 -> 26 [ label = "'!'..'~'" ];
25 -> err_25 [ label = "DEF / err_appname" ];
26 -> 27 [ label = "'!'..'~'" ];
26 -> err_26 [ label = "DEF / err_appname" ];
27 -> 28 [ label = "'!'..'~'" ];
27 -> err_27 [ label = "DEF / err_appname" ];
28 -> 29 [ label = "'!'..'~'" ];
28 -> err_28 [ label = "DEF / err_appname" ];
29 -> 30 [ label = "'!'..'~'" ];
29 -> err_29 [ label = "DEF / err_appname" ];
30 -> 31 [ label = "'!'..'~'" ];
30 -> err_30 [ label = "DEF / err_appname" ];
31 -> 32 [ label = "'!'..'~'" ];
31 -> err_31 [ label = "DEF / err_appname" ];
32 -> 33 [ label = "'!'..'~'" ];
32 -> err_32 [ label = "DEF / err_appname" ];
33 -> 34 [ label = "'!'..'~'" ];
33 -> err_33 [ label = "DEF / err_appname" ];
34 -> 35 [ label = "'!'..'~'" ];
34 -> err_34 [ label = "DEF / err_appname" ];
35 -> 36 [ label = "'!'..'~'" ];
35 -> err_35 [ label = "DEF / err_appname" ];
36 -> 37 [ label = "'!'..'~'" ];
36 -> err_36 [ label = "DEF / err_appname" ];
37 -> 38 [ label = "'!'..'~'" ];
37 -> err_37 [ label = "DEF / err_appname" ];
38 -> 39 [ label = "'!'..'~'" ];
38 -> err_38 [ label = "DEF / err_appname" ];
39 -> 40 [ label = "'!'..'~'" ];
39 -> err_39 [ label = "DEF / err_appname" ];
40 -> 41 [ label = "'!'..'~'" ];
40 -> err_40 [ label = "DEF / err_appname" ];
41 -> 42 [ label = "'!'..'~'" ];
41 -> err_41 [ label = "DEF / err_appname" ];
42 -> 43 [ label = "'!'..'~'" ];
42 -> err_42 [ label = "DEF / err_appname" ];
43 -> 44 [ label = "'!'..'~'" ];
43 -> err_43 [ label = "DEF / err_appname" ];
44 -> 45 [ label = "'!'..'~'" ];
44 -> err_44 [ label = "DEF / err_appname" ];
45 -> 46 [ label = "'!'..'~'" ];
45 -> err_45 [ label = "DEF / err_appname" ];
46 -> 47 [ label = "'!'..'~'" ];
46 -> err_46 [ label = "DEF / err_appname" ];
47 -> 48 [ label = "'!'..'~'" ];
47 -> err_47 [ label = "DEF / err_appname" ];
48 -> 49 [ label = "'!'..'~'" ];
48 -> err_48 [ label = "DEF / err_appname" ];
49 -> err_49 [ label = "DEF / err_appname" ];
ENTRY -> 1 [ label = "IN" ];
1 -> eof_1 [ label = "EOF / err_appname" ];
2 -> eof_2 [ label = "EOF / set_appname" ];
3 -> eof_3 [ label = "EOF / set_appname" ];
4 -> eof_4 [ label = "EOF / set_appname" ];
5 -> eof_5 [ label = "EOF / set_appname" ];
6 -> eof_6 [ label = "EOF / set_appname" ];
7 -> eof_7 [ label = "EOF / set_appname" ];
8 -> eof_8 [ label = "EOF / set_appname" ];
9 -> eof_9 [ label = "EOF / set_appname" ];
10 -> eof_10 [ label = "EOF / set_appname" ];
11 -> eof_11 [ label = "EOF / set_appname" ];
12 -> eof_12 [ label = "EOF / set_appname" ];
13 -> eof_13 [ label = "EOF / set_appname" ];
14 -> eof_14 [ label = "EOF / set_appname" ];
15 -> eof_15 [ label = "EOF / set_appname" ];
16 -> eof_16 [ label = "EOF / set_appname" ];
17 -> eof_17 [ label = "EOF / set_appname" ];
18 -> eof_18 [ label = "EOF / set_appname" ];
19 -> eof_19 [ label = "EOF / set_appname" ];
20 -> eof_20 [ label = "EOF / set_appname" ];
21 -> eof_21 [ label = "EOF / set_appname" ];
22 -> eof_22 [ label = "EOF / set_appname" ];
23 -> eof_23 [ label = "EOF / set_appname" ];
24 -> eof_24 [ label = "EOF / set_appname" ];
25 -> eof_25 [ label = "EOF / set_appname" ];
26 -> eof_26 [ label = "EOF / set_appname" ];
27 -> eof_27 [ label = "EOF / set_appname" ];
28 -> eof_28 [ label = "EOF / set_appname" ];
29 -> eof_29 [ label = "EOF / set_appname" ];
30 -> eof_30 [ label = "EOF / set_appname" ];
31 -> eof_31 [ label = "EOF / set_appname" ];
32 -> eof_32 [ label = "EOF / set_appname" ];
33 -> eof_33 [ label = "EOF / set_appname" ];
34 -> eof_34 [ label = "EOF / set_appname" ];
35 -> eof_35 [ label = "EOF / set_appname" ];
36 -> eof_36 [ label = "EOF / set_appname" ];
37 -> eof_37 [ label = "EOF / set_appname" ];
38 -> eof_38 [ label = "EOF / set_appname" ];
39 -> eof_39 [ label = "EOF / set_appname" ];
40 -> eof_40 [ label = "EOF / set_appname" ];
41 -> eof_41 [ label = "EOF / set_appname" ];
42 -> eof_42 [ label = "EOF / set_appname" ];
43 -> eof_43 [ label = "EOF / set_appname" ];
44 -> eof_44 [ label = "EOF / set_appname" ];
45 -> eof_45 [ label = "EOF / set_appname" ];
46 -> eof_46 [ label = "EOF / set_appname" ];
47 -> eof_47 [ label = "EOF / set_appname" ];
48 -> eof_48 [ label = "EOF / set_appname" ];
49 -> eof_49 [ label = "EOF / set_appname" ];
}
This diff is collapsed.
digraph rfc5424 {
rankdir=LR;
node [ shape = point ];
ENTRY;
eof_1;
eof_2;
eof_3;
eof_4;
eof_5;
eof_6;
eof_7;
eof_8;
eof_9;
node [ shape = circle, height = 0.2 ];
err_1 [ label=""];
err_2 [ label=""];
err_3 [ label=""];
err_4 [ label=""];
err_5 [ label=""];
err_6 [ label=""];
err_7 [ label=""];
err_8 [ label=""];
err_9 [ label=""];
node [ fixedsize = true, height = 0.65, shape = doublecircle ];
8;
9;
node [ shape = circle ];
1 -> 9 [ label = "128..191" ];
1 -> err_1 [ label = "DEF / err_msg" ];
2 -> 1 [ label = "160..191" ];
2 -> err_2 [ label = "DEF / err_msg" ];
3 -> 1 [ label = "128..191" ];
3 -> err_3 [ label = "DEF / err_msg" ];
4 -> 1 [ label = "128..159" ];
4 -> err_4 [ label = "DEF / err_msg" ];
5 -> 3 [ label = "144..191" ];
5 -> err_5 [ label = "DEF / err_msg" ];
6 -> 3 [ label = "128..191" ];
6 -> err_6 [ label = "DEF / err_msg" ];
7 -> 3 [ label = "128..143" ];
7 -> err_7 [ label = "DEF / err_msg" ];
8 -> err_8 [ label = "128..193, 245..255 / err_msg" ];
8 -> 1 [ label = "194..223 / mark, markmsg" ];
8 -> 2 [ label = "224 / mark, markmsg" ];
8 -> 3 [ label = "225..236, 238..239 / mark, markmsg" ];
8 -> 4 [ label = "237 / mark, markmsg" ];
8 -> 5 [ label = "240 / mark, markmsg" ];
8 -> 6 [ label = "241..243 / mark, markmsg" ];
8 -> 7 [ label = "244 / mark, markmsg" ];
8 -> 9 [ label = "DEF / mark, markmsg" ];
9 -> err_9 [ label = "128..193, 245..255 / err_msg" ];
9 -> 1 [ label = "194..223" ];
9 -> 2 [ label = "224" ];
9 -> 3 [ label = "225..236, 238..239" ];
9 -> 4 [ label = "237" ];
9 -> 5 [ label = "240" ];
9 -> 6 [ label = "241..243" ];
9 -> 7 [ label = "244" ];
9 -> 9 [ label = "DEF" ];
ENTRY -> 8 [ label = "IN" ];
1 -> eof_1 [ label = "EOF / err_msg" ];
2 -> eof_2 [ label = "EOF / err_msg" ];
3 -> eof_3 [ label = "EOF / err_msg" ];
4 -> eof_4 [ label = "EOF / err_msg" ];
5 -> eof_5 [ label = "EOF / err_msg" ];
6 -> eof_6 [ label = "EOF / err_msg" ];
7 -> eof_7 [ label = "EOF / err_msg" ];
8 -> eof_8 [ label = "EOF / mark, markmsg, set_msg" ];
9 -> eof_9 [ label = "EOF / set_msg" ];
}
digraph rfc5424 {
rankdir=LR;
node [ shape = point ];
ENTRY;
eof_1;
eof_2;
eof_3;
eof_4;
eof_5;
eof_6;
eof_7;
eof_8;
eof_9;
eof_10;
eof_11;
eof_12;
eof_13;
eof_14;
eof_15;
eof_16;
eof_17;
eof_18;