bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/scollector/collectors/httpunit.go (about)

     1  package collectors
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"bosun.org/slog"
     8  
     9  	"bosun.org/metadata"
    10  	"bosun.org/opentsdb"
    11  	"github.com/BurntSushi/toml"
    12  	"github.com/StackExchange/httpunit"
    13  )
    14  
    15  func HTTPUnitTOML(filename string, freq time.Duration) error {
    16  	var plans httpunit.Plans
    17  	if _, err := toml.DecodeFile(filename, &plans); err != nil {
    18  		return err
    19  	}
    20  	HTTPUnitPlans(filename, &plans, freq)
    21  	return nil
    22  }
    23  
    24  func HTTPUnitHiera(filename string, freq time.Duration) error {
    25  	plans, err := httpunit.ExtractHiera(filename)
    26  	if err != nil {
    27  		return err
    28  	}
    29  	HTTPUnitPlans(filename, &httpunit.Plans{Plans: plans}, freq)
    30  	return nil
    31  }
    32  
    33  func HTTPUnitPlans(name string, plans *httpunit.Plans, freq time.Duration) {
    34  	collectors = append(collectors, &IntervalCollector{
    35  		F: func() (opentsdb.MultiDataPoint, error) {
    36  			return cHTTPUnit(plans)
    37  		},
    38  		name:     fmt.Sprintf("c_httpunit_%s", name),
    39  		Interval: freq,
    40  	})
    41  }
    42  
    43  func cHTTPUnit(plans *httpunit.Plans) (opentsdb.MultiDataPoint, error) {
    44  	ch, _, err := plans.Test("", false, nil, nil)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	unix_now := time.Now().Unix()
    49  	var md opentsdb.MultiDataPoint
    50  	for r := range ch {
    51  		if r == nil || r.Case == nil || r.Plan == nil {
    52  			slog.Errorf("httpunit: unexpected test plan on channel, the plan result, the case, and/or the plan result is missing.")
    53  			continue
    54  		}
    55  		tags := opentsdb.TagSet{
    56  			"protocol":     r.Case.URL.Scheme,
    57  			"ip":           r.Case.IP.String(),
    58  			"url_host":     r.Case.URL.Host,
    59  			"hc_test_case": r.Plan.Label,
    60  		}
    61  		metadata.AddMeta("", opentsdb.TagSet{"hc_test_case": r.Plan.Label}, "url", r.Case.URL.String(), false)
    62  		if r.Result == nil || r.Result.Result != nil {
    63  			Add(&md, "hu.error", true, tags, metadata.Gauge, metadata.Bool, descHTTPUnitError)
    64  			if r.Result == nil {
    65  				continue
    66  			}
    67  		}
    68  		Add(&md, "hu.error", false, tags, metadata.Gauge, metadata.Bool, descHTTPUnitError)
    69  		ms := int64(r.Result.TimeTotal / time.Millisecond)
    70  		Add(&md, "hu.socket_connected", r.Result.Connected, tags, metadata.Gauge, metadata.Bool, descHTTPUnitSocketConnected)
    71  		Add(&md, "hu.time_total", ms, tags, metadata.Gauge, metadata.MilliSecond, descHTTPUnitTotalTime)
    72  		code := 0
    73  		if r.Result.Resp != nil {
    74  			code = r.Result.Resp.StatusCode
    75  		}
    76  		Add(&md, "hu.response_code", code, tags, metadata.Gauge, metadata.StatusCode, descHTTPUnitStatusCode)
    77  		switch r.Case.URL.Scheme {
    78  		case "http", "https":
    79  			Add(&md, "hu.http.got_expected_code", r.Result.GotCode, tags, metadata.Gauge, metadata.Bool, descHTTPUnitExpectedCode)
    80  			Add(&md, "hu.http.got_expected_text", r.Result.GotText, tags, metadata.Gauge, metadata.Bool, descHTTPUnitExpectedText)
    81  			Add(&md, "hu.http.got_expected_regex", r.Result.GotRegex, tags, metadata.Gauge, metadata.Bool, descHTTPUnitExpectedRegex)
    82  			if r.Case.URL.Scheme == "https" {
    83  				Add(&md, "hu.cert.valid", !r.Result.InvalidCert, tags, metadata.Gauge, metadata.Bool, descHTTPUnitCertValid)
    84  				if resp := r.Result.Resp; resp != nil && resp.TLS != nil && len(resp.TLS.PeerCertificates) > 0 {
    85  					expiration := resp.TLS.PeerCertificates[0].NotAfter.Unix()
    86  					Add(&md, "hu.cert.expires", expiration, tags, metadata.Gauge, metadata.Timestamp, descHTTPUnitCertExpires)
    87  					Add(&md, "hu.cert.valid_for", expiration-unix_now, tags, metadata.Gauge, metadata.Second, descHTTPUnitCertValidFor)
    88  				}
    89  			}
    90  		}
    91  	}
    92  	return md, nil
    93  }
    94  
    95  const (
    96  	descHTTPUnitError           = "1 if any error (no connection, unexpected code or text) occurred, else 0."
    97  	descHTTPUnitSocketConnected = "1 if a connection was made, else 0."
    98  	descHTTPUnitExpectedCode    = "1 if the HTTP status code was expected, else 0."
    99  	descHTTPUnitExpectedText    = "1 if the response contained expected text, else 0."
   100  	descHTTPUnitExpectedRegex   = "1 if the response matched expected regex, else 0."
   101  	descHTTPUnitCertValid       = "1 if the SSL certificate is valid, else 0."
   102  	descHTTPUnitCertExpires     = "Unix epoch time of the certificate expiration."
   103  	descHTTPUnitCertValidFor    = "Number of seconds until certificate expiration."
   104  	descHTTPUnitTotalTime       = "Total time consumed by test case."
   105  	descHTTPUnitStatusCode      = "The HTTP status response code of the response, or 0 if no response."
   106  )