github.com/newrelic/go-agent@v3.26.0+incompatible/internal/utilities.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 "bytes" 8 "encoding/json" 9 "fmt" 10 "net/http" 11 "strconv" 12 "strings" 13 "time" 14 ) 15 16 // JSONString assists in logging JSON: Based on the formatter used to log 17 // Context contents, the contents could be marshalled as JSON or just printed 18 // directly. 19 type JSONString string 20 21 // MarshalJSON returns the JSONString unmodified without any escaping. 22 func (js JSONString) MarshalJSON() ([]byte, error) { 23 if "" == js { 24 return []byte("null"), nil 25 } 26 return []byte(js), nil 27 } 28 29 func removeFirstSegment(name string) string { 30 idx := strings.Index(name, "/") 31 if -1 == idx { 32 return name 33 } 34 return name[idx+1:] 35 } 36 37 func timeToFloatSeconds(t time.Time) float64 { 38 return float64(t.UnixNano()) / float64(1000*1000*1000) 39 } 40 41 func timeToFloatMilliseconds(t time.Time) float64 { 42 return float64(t.UnixNano()) / float64(1000*1000) 43 } 44 45 // FloatSecondsToDuration turns a float64 in seconds into a time.Duration. 46 func FloatSecondsToDuration(seconds float64) time.Duration { 47 nanos := seconds * 1000 * 1000 * 1000 48 return time.Duration(nanos) * time.Nanosecond 49 } 50 51 func absTimeDiff(t1, t2 time.Time) time.Duration { 52 if t1.After(t2) { 53 return t1.Sub(t2) 54 } 55 return t2.Sub(t1) 56 } 57 58 // CompactJSONString removes the whitespace from a JSON string. This function 59 // will panic if the string provided is not valid JSON. Thus is must only be 60 // used in testing code! 61 func CompactJSONString(js string) string { 62 buf := new(bytes.Buffer) 63 if err := json.Compact(buf, []byte(js)); err != nil { 64 panic(fmt.Errorf("unable to compact JSON: %v", err)) 65 } 66 return buf.String() 67 } 68 69 // GetContentLengthFromHeader gets the content length from a HTTP header, or -1 70 // if no content length is available. 71 func GetContentLengthFromHeader(h http.Header) int64 { 72 if cl := h.Get("Content-Length"); cl != "" { 73 if contentLength, err := strconv.ParseInt(cl, 10, 64); err == nil { 74 return contentLength 75 } 76 } 77 78 return -1 79 } 80 81 // StringLengthByteLimit truncates strings using a byte-limit boundary and 82 // avoids terminating in the middle of a multibyte character. 83 func StringLengthByteLimit(str string, byteLimit int) string { 84 if len(str) <= byteLimit { 85 return str 86 } 87 88 limitIndex := 0 89 for pos := range str { 90 if pos > byteLimit { 91 break 92 } 93 limitIndex = pos 94 } 95 return str[0:limitIndex] 96 } 97 98 func timeFromUnixMilliseconds(millis uint64) time.Time { 99 secs := int64(millis) / 1000 100 msecsRemaining := int64(millis) % 1000 101 nsecsRemaining := msecsRemaining * (1000 * 1000) 102 return time.Unix(secs, nsecsRemaining) 103 } 104 105 // TimeToUnixMilliseconds converts a time into a Unix timestamp in millisecond 106 // units. 107 func TimeToUnixMilliseconds(tm time.Time) uint64 { 108 return uint64(tm.UnixNano()) / uint64(1000*1000) 109 } 110 111 // MinorVersion takes a given version string and returns only the major and 112 // minor portions of it. If the input is malformed, it returns the input 113 // untouched. 114 func MinorVersion(v string) string { 115 split := strings.SplitN(v, ".", 3) 116 if len(split) < 2 { 117 return v 118 } 119 return split[0] + "." + split[1] 120 }