github.com/mackerelio/mackerel-agent-plugins@v0.89.3/mackerel-plugin-accesslog/lib/accesslog_test.go (about) 1 package mpaccesslog 2 3 import ( 4 "encoding/json" 5 "os" 6 "path/filepath" 7 "reflect" 8 "runtime" 9 "testing" 10 11 "github.com/Songmu/axslogparser" 12 ) 13 14 var fetchMetricsTests = []struct { 15 Name string 16 InFile string 17 Output map[string]float64 18 }{ 19 { 20 Name: "Apache log", 21 InFile: "testdata/sample-apache.log", 22 Output: map[string]float64{ 23 "total_count": 10, 24 "2xx_count": 7, 25 "3xx_count": 0, 26 "4xx_count": 2, 27 "5xx_count": 1, 28 "2xx_percentage": 70, 29 "3xx_percentage": 0, 30 "4xx_percentage": 20, 31 "5xx_percentage": 10, 32 }, 33 }, 34 { 35 Name: "Apache log (loose)", 36 InFile: "testdata/sample-apache-loose.log", 37 Output: map[string]float64{ 38 "total_count": 2, 39 "2xx_count": 2, 40 "3xx_count": 0, 41 "4xx_count": 0, 42 "5xx_count": 0, 43 "2xx_percentage": 100, 44 "3xx_percentage": 0, 45 "4xx_percentage": 0, 46 "5xx_percentage": 0, 47 }, 48 }, 49 { 50 Name: "LTSV log", 51 InFile: "testdata/sample-ltsv.tsv", 52 Output: map[string]float64{ 53 "2xx_count": 7, 54 "3xx_count": 1, 55 "4xx_count": 1, 56 "5xx_count": 1, 57 "total_count": 10, 58 "2xx_percentage": 70, 59 "3xx_percentage": 10, 60 "4xx_percentage": 10, 61 "5xx_percentage": 10, 62 "average": 0.7603999999999999, 63 "90_percentile": 2.018, 64 "95_percentile": 3.018, 65 "99_percentile": 3.018, 66 }, 67 }, 68 { 69 Name: "LTSV long line log", 70 InFile: "testdata/sample-ltsv-long.tsv", 71 Output: map[string]float64{ 72 "2xx_count": 2, 73 "3xx_count": 0, 74 "4xx_count": 0, 75 "5xx_count": 0, 76 "total_count": 2, 77 "2xx_percentage": 100, 78 "3xx_percentage": 0, 79 "4xx_percentage": 0, 80 "5xx_percentage": 0, 81 "average": 0.015, 82 "90_percentile": 0.015, 83 "95_percentile": 0.015, 84 "99_percentile": 0.015, 85 }, 86 }, 87 { 88 Name: "LTSV log (loose)", 89 InFile: "testdata/sample-ltsv-loose.tsv", 90 Output: map[string]float64{ 91 "2xx_count": 3, 92 "3xx_count": 0, 93 "4xx_count": 0, 94 "5xx_count": 0, 95 "total_count": 3, 96 "2xx_percentage": 100, 97 "3xx_percentage": 0, 98 "4xx_percentage": 0, 99 "5xx_percentage": 0, 100 "average": 0.020, 101 "90_percentile": 0.025, 102 "95_percentile": 0.025, 103 "99_percentile": 0.025, 104 }, 105 }, 106 { 107 Name: "LTSV log (reqtime microsec)", 108 InFile: "testdata/sample-ltsv-reqtime-microsec.tsv", 109 Output: map[string]float64{ 110 "2xx_count": 7, 111 "3xx_count": 1, 112 "4xx_count": 1, 113 "5xx_count": 1, 114 "total_count": 10, 115 "2xx_percentage": 70, 116 "3xx_percentage": 10, 117 "4xx_percentage": 10, 118 "5xx_percentage": 10, 119 "average": 0.00036090000000000004, 120 "90_percentile": 0.000628, 121 "95_percentile": 0.0008155, 122 "99_percentile": 0.0008155, 123 }, 124 }, 125 } 126 127 func TestFetchMetrics(t *testing.T) { 128 for _, tt := range fetchMetricsTests { 129 t.Logf("testing: %s", tt.Name) 130 p := &AccesslogPlugin{ 131 file: tt.InFile, 132 noPosFile: true, 133 } 134 out, err := p.FetchMetrics() 135 if err != nil { 136 t.Errorf("%s(err): error should be nil but: %+v", tt.Name, err) 137 continue 138 } 139 if !reflect.DeepEqual(out, tt.Output) { 140 t.Errorf("%s: \n out: %#v\n want: %#v", tt.Name, out, tt.Output) 141 } 142 } 143 } 144 145 func TestFetchMetricsWithCustomParser(t *testing.T) { 146 // OK case 147 p := &AccesslogPlugin{ 148 file: "testdata/sample-ltsv.tsv", 149 noPosFile: true, 150 parser: &axslogparser.LTSV{}, 151 } 152 out, err := p.FetchMetrics() 153 if err != nil { 154 t.Errorf("error should be nil but: %+v", err) 155 return 156 } 157 158 expected := map[string]float64{ 159 "2xx_count": 7, 160 "3xx_count": 1, 161 "4xx_count": 1, 162 "5xx_count": 1, 163 "total_count": 10, 164 "2xx_percentage": 70, 165 "3xx_percentage": 10, 166 "4xx_percentage": 10, 167 "5xx_percentage": 10, 168 "average": 0.7603999999999999, 169 "90_percentile": 2.018, 170 "95_percentile": 3.018, 171 "99_percentile": 3.018, 172 } 173 if !reflect.DeepEqual(out, expected) { 174 t.Errorf("out: %#v\n want: %#v", out, expected) 175 } 176 177 // NG case (should not detect log format by log line) 178 p = &AccesslogPlugin{ 179 file: "testdata/sample-apache.log", 180 noPosFile: true, 181 parser: &axslogparser.LTSV{}, 182 } 183 out, err = p.FetchMetrics() 184 if err != nil { 185 t.Errorf("error should be nil but: %+v", err) 186 return 187 } 188 189 expected = map[string]float64{ 190 "2xx_count": 0, 191 "3xx_count": 0, 192 "4xx_count": 0, 193 "5xx_count": 0, 194 "total_count": 0, 195 } 196 if !reflect.DeepEqual(out, expected) { 197 t.Errorf("out: %#v\n want: %#v", out, expected) 198 } 199 } 200 201 func TestSkipLogOnceIfNoPos(t *testing.T) { 202 if runtime.GOOS == "windows" { 203 t.Skip("skipping test on windows") 204 } 205 dir := t.TempDir() 206 posFile := filepath.Join(dir, "plugin-accesslog.test.pos") 207 p := &AccesslogPlugin{ 208 file: "testdata/sample-ltsv.tsv", 209 posFile: posFile, 210 } 211 out, err := p.FetchMetrics() 212 if err != nil { 213 t.Errorf("error should be nil but: %+v", err) 214 return 215 } 216 if n := len(out); n != 0 { 217 t.Errorf("got %d metrics; but want 0", n) 218 } 219 220 // see https://github.com/Songmu/postailer/blob/master/postailer.go#L27-L30 221 var pos struct { 222 Pos int64 `json:"pos"` 223 } 224 b, err := os.ReadFile(posFile) 225 if err != nil { 226 t.Errorf("ReadFile(%s): %v", posFile, err) 227 return 228 } 229 if err := json.Unmarshal(b, &pos); err != nil { 230 t.Fatal(err) 231 } 232 var want int64 = 1247 233 if pos.Pos != want { 234 t.Errorf("saved position = %d; want %d", pos.Pos, want) 235 } 236 }