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  }