github.com/newrelic/go-agent@v3.26.0+incompatible/internal/queuing.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package internal
     5  
     6  import (
     7  	"net/http"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  )
    12  
    13  const (
    14  	xRequestStart = "X-Request-Start"
    15  	xQueueStart   = "X-Queue-Start"
    16  )
    17  
    18  var (
    19  	earliestAcceptableSeconds = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()
    20  	latestAcceptableSeconds   = time.Date(2050, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()
    21  )
    22  
    23  func checkQueueTimeSeconds(secondsFloat float64) time.Time {
    24  	seconds := int64(secondsFloat)
    25  	nanos := int64((secondsFloat - float64(seconds)) * (1000.0 * 1000.0 * 1000.0))
    26  	if seconds > earliestAcceptableSeconds && seconds < latestAcceptableSeconds {
    27  		return time.Unix(seconds, nanos)
    28  	}
    29  	return time.Time{}
    30  }
    31  
    32  func parseQueueTime(s string) time.Time {
    33  	f, err := strconv.ParseFloat(s, 64)
    34  	if nil != err {
    35  		return time.Time{}
    36  	}
    37  	if f <= 0 {
    38  		return time.Time{}
    39  	}
    40  
    41  	// try microseconds
    42  	if t := checkQueueTimeSeconds(f / (1000.0 * 1000.0)); !t.IsZero() {
    43  		return t
    44  	}
    45  	// try milliseconds
    46  	if t := checkQueueTimeSeconds(f / (1000.0)); !t.IsZero() {
    47  		return t
    48  	}
    49  	// try seconds
    50  	if t := checkQueueTimeSeconds(f); !t.IsZero() {
    51  		return t
    52  	}
    53  	return time.Time{}
    54  }
    55  
    56  // QueueDuration TODO
    57  func QueueDuration(hdr http.Header, txnStart time.Time) time.Duration {
    58  	s := hdr.Get(xQueueStart)
    59  	if "" == s {
    60  		s = hdr.Get(xRequestStart)
    61  	}
    62  	if "" == s {
    63  		return 0
    64  	}
    65  
    66  	s = strings.TrimPrefix(s, "t=")
    67  	qt := parseQueueTime(s)
    68  	if qt.IsZero() {
    69  		return 0
    70  	}
    71  	if qt.After(txnStart) {
    72  		return 0
    73  	}
    74  	return txnStart.Sub(qt)
    75  }