github.com/apex/up@v1.7.1/internal/logs/parser/parser_test.go (about) 1 package parser 2 3 import ( 4 "testing" 5 ) 6 7 // TODO: precedence... 8 // TODO: byte size literals 9 // TODO: support literals: `method = GET`, `ip = 70.*` etc 10 // TODO: error tests 11 // TODO: test error messages 12 // TODO: add "starts with" / "ends with" to compliment "contains"? 13 // TODO: document best practices for logging json from an app 14 15 var cases = []struct { 16 Input string 17 Output string 18 }{ 19 {`production`, `{ $.fields.stage = "production" }`}, 20 {`development`, `{ $.fields.stage = "development" }`}, 21 {`staging`, `{ $.fields.stage = "staging" }`}, 22 {`method = "GET"`, `{ $.fields.method = "GET" }`}, 23 {`debug`, `{ ($.level = "debug") }`}, 24 {`info`, `{ ($.level = "info") }`}, 25 {`warn`, `{ ($.level = "warn") }`}, 26 {`error`, `{ ($.level = "error") }`}, 27 {`fatal`, `{ ($.level = "fatal") }`}, 28 {`not info`, `{ !(($.level = "info")) }`}, 29 {`not error or fatal`, `{ !(($.level = "error") || ($.level = "fatal")) }`}, 30 {`!info`, `{ !($.level = "info") }`}, 31 {`level = "info"`, `{ $.level = "info" }`}, 32 {`message = "user signin"`, `{ $.message = "user signin" }`}, 33 {`email = "tj@apex.sh"`, `{ $.fields.email = "tj@apex.sh" }`}, 34 {`status = 0`, `{ $.fields.status = 0 }`}, 35 {`status = 0.123`, `{ $.fields.status = 0.123 }`}, 36 {`status = .123`, `{ $.fields.status = 0.123 }`}, 37 {`status = 200`, `{ $.fields.status = 200 }`}, 38 {`price = 1.95`, `{ $.fields.price = 1.95 }`}, 39 {`price == 1.95`, `{ $.fields.price = 1.95 }`}, 40 {`price > 1.95`, `{ $.fields.price > 1.95 }`}, 41 {`price < 1.95`, `{ $.fields.price < 1.95 }`}, 42 {`price >= 1.95`, `{ $.fields.price >= 1.95 }`}, 43 {`price <= 1.95`, `{ $.fields.price <= 1.95 }`}, 44 {`price != 1.95`, `{ $.fields.price != 1.95 }`}, 45 {`!enabled`, `{ !$.fields.enabled }`}, 46 {`! enabled`, `{ !$.fields.enabled }`}, 47 {`foo = 1 || bar = 2`, `{ $.fields.foo = 1 || $.fields.bar = 2 }`}, 48 {`foo = 1 && bar = 2`, `{ $.fields.foo = 1 && $.fields.bar = 2 }`}, 49 {`foo = 1 or bar = 2`, `{ $.fields.foo = 1 || $.fields.bar = 2 }`}, 50 {`foo = 1 and bar = 2`, `{ $.fields.foo = 1 && $.fields.bar = 2 }`}, 51 {`foo = 1 bar = 2`, `{ $.fields.foo = 1 && $.fields.bar = 2 }`}, 52 {`foo.bar.baz = 1`, `{ $.fields.foo.bar.baz = 1 }`}, 53 {`level = "error" and (duration >= 500 or duration = 0)`, `{ $.level = "error" && ($.fields.duration >= 500 || $.fields.duration = 0) }`}, 54 {`level = "error" (duration >= 500 or duration = 0)`, `{ $.level = "error" && ($.fields.duration >= 500 || $.fields.duration = 0) }`}, 55 {`cart.total = 15.99`, `{ $.fields.cart.total = 15.99 }`}, 56 {`user.name contains "obi"`, `{ $.fields.user.name = "*obi*" }`}, 57 {`user in ("Tobi")`, `{ ($.fields.user = "Tobi") }`}, 58 {`pet.age in (1, 2, 3)`, `{ ($.fields.pet.age = 1 || $.fields.pet.age = 2 || $.fields.pet.age = 3) }`}, 59 {`user in ("Tobi", "Loki", "Jane")`, `{ ($.fields.user = "Tobi" || $.fields.user = "Loki" || $.fields.user = "Jane") }`}, 60 {`user.name in ("Tobi", "Loki", "Jane")`, `{ ($.fields.user.name = "Tobi" || $.fields.user.name = "Loki" || $.fields.user.name = "Jane") }`}, 61 {`not user.admin`, `{ !($.fields.user.admin) }`}, 62 {`not user.role in ("Admin", "Moderator")`, `{ !(($.fields.user.role = "Admin" || $.fields.user.role = "Moderator")) }`}, 63 {`user.role not in ("Admin", "Moderator")`, `{ !(($.fields.user.role = "Admin" || $.fields.user.role = "Moderator")) }`}, 64 {`not level = "error" or level = "fatal"`, `{ !($.level = "error" || $.level = "fatal") }`}, 65 {`cart.products[0] = "something"`, `{ $.fields.cart.products[0] = "something" }`}, 66 {`cart.products[0].price = 15.99`, `{ $.fields.cart.products[0].price = 15.99 }`}, 67 {`cart.products[0][1].price = 15.99`, `{ $.fields.cart.products[0][1].price = 15.99 }`}, 68 {`cart.products[0].items[1].price = 15.99`, `{ $.fields.cart.products[0].items[1].price = 15.99 }`}, 69 {`user.name in ("Tobi", "Loki") and status >= 500`, `{ ($.fields.user.name = "Tobi" || $.fields.user.name = "Loki") && $.fields.status >= 500 }`}, 70 {`method in ("POST", "PUT") and ip = "207.*" and status = 200 and duration >= 50`, `{ ($.fields.method = "POST" || $.fields.method = "PUT") && $.fields.ip = "207.*" && $.fields.status = 200 && $.fields.duration >= 50 }`}, 71 {`method in ("POST", "PUT") ip = "207.*" status = 200 duration >= 50`, `{ ($.fields.method = "POST" || $.fields.method = "PUT") && $.fields.ip = "207.*" && $.fields.status = 200 && $.fields.duration >= 50 }`}, 72 {`size > 1kb`, `{ $.fields.size > 1024 }`}, 73 {`size > 2kb`, `{ $.fields.size > 2048 }`}, 74 {`size > 1.5mb`, `{ $.fields.size > 1572864 }`}, 75 {`size > 100b`, `{ $.fields.size > 100 }`}, 76 {`duration > 100ms`, `{ $.fields.duration > 100 }`}, 77 {`duration > 1s`, `{ $.fields.duration > 1000 }`}, 78 {`duration > 4.5s`, `{ $.fields.duration > 4500 }`}, 79 {`"User Login"`, `{ $.message = "User Login" }`}, 80 {`"User*"`, `{ $.message = "User*" }`}, 81 {`"Signup" or "Signin"`, `{ $.message = "Signup" || $.message = "Signin" }`}, 82 {`"User Login" method = "GET"`, `{ $.message = "User Login" && $.fields.method = "GET" }`}, 83 {`method = GET`, `{ $.fields.method = "GET" }`}, 84 {`method in (GET, HEAD, OPTIONS)`, `{ ($.fields.method = "GET" || $.fields.method = "HEAD" || $.fields.method = "OPTIONS") }`}, 85 {`name = tj`, `{ $.fields.name = "tj" }`}, 86 {`method = GET path = /account/billing`, `{ $.fields.method = "GET" && $.fields.path = "/account/billing" }`}, 87 {`cart.products[0].name = ps4`, `{ $.fields.cart.products[0].name = "ps4" }`}, 88 {`path = "/_health"`, `{ $.fields.path = "/_health" }`}, 89 {`path == "/_health"`, `{ $.fields.path = "/_health" }`}, 90 {`path > "/_health"`, `{ $.fields.path > "/_health" }`}, 91 {`path >= "/_health"`, `{ $.fields.path >= "/_health" }`}, 92 {`path != "/_health"`, `{ $.fields.path != "/_health" }`}, 93 } 94 95 func TestParse(t *testing.T) { 96 for _, c := range cases { 97 t.Logf("parsing %q", c.Input) 98 n, err := Parse(c.Input) 99 100 if err != nil { 101 t.Errorf("error parsing %q: %s", c.Input, err) 102 continue 103 } 104 105 if n.String() != c.Output { 106 t.Errorf("\n\ntext: %s\nwant: %s\n got: %s\n\n", c.Input, c.Output, n.String()) 107 } 108 } 109 } 110 111 func BenchmarkParse(b *testing.B) { 112 for i := 0; i < b.N; i++ { 113 Parse(`user.name in ("Tobi", "Loki", "Jane")`) 114 } 115 }