1// +build go1.13 2 3// Copyright (c) Microsoft Corporation. All rights reserved. 4// Licensed under the MIT License. 5 6package azcore 7 8import ( 9 "bytes" 10 "fmt" 11 "os" 12 "runtime" 13 "strings" 14) 15 16// TelemetryOptions configures the telemetry policy's behavior. 17type TelemetryOptions struct { 18 // Value is a string prepended to each request's User-Agent and sent to the service. 19 // The service records the user-agent in logs for diagnostics and tracking of client requests. 20 Value string 21 22 // ApplicationID is an application-specific identification string used in telemetry. 23 // It has a maximum length of 24 characters and must not contain any spaces. 24 ApplicationID string 25 26 // Disabled will prevent the addition of any telemetry data to the User-Agent. 27 Disabled bool 28} 29 30type telemetryPolicy struct { 31 telemetryValue string 32} 33 34// NewTelemetryPolicy creates a telemetry policy object that adds telemetry information to outgoing HTTP requests. 35// The format is [<application_id> ]azsdk-<sdk_language>-<package_name>/<package_version> <platform_info> [<custom>]. 36// Pass nil to accept the default values; this is the same as passing a zero-value options. 37func NewTelemetryPolicy(o *TelemetryOptions) Policy { 38 if o == nil { 39 o = &TelemetryOptions{} 40 } 41 tp := telemetryPolicy{} 42 if o.Disabled { 43 return &tp 44 } 45 b := &bytes.Buffer{} 46 // normalize ApplicationID 47 if o.ApplicationID != "" { 48 o.ApplicationID = strings.ReplaceAll(o.ApplicationID, " ", "/") 49 if len(o.ApplicationID) > 24 { 50 o.ApplicationID = o.ApplicationID[:24] 51 } 52 b.WriteString(o.ApplicationID) 53 b.WriteRune(' ') 54 } 55 // write out telemetry string 56 if o.Value != "" { 57 b.WriteString(o.Value) 58 b.WriteRune(' ') 59 } 60 b.WriteString(UserAgent) 61 b.WriteRune(' ') 62 b.WriteString(platformInfo) 63 tp.telemetryValue = b.String() 64 return &tp 65} 66 67func (p telemetryPolicy) Do(req *Request) (*Response, error) { 68 if p.telemetryValue == "" { 69 return req.Next() 70 } 71 // preserve the existing User-Agent string 72 if ua := req.Request.Header.Get(HeaderUserAgent); ua != "" { 73 p.telemetryValue = fmt.Sprintf("%s %s", p.telemetryValue, ua) 74 } 75 var rt requestTelemetry 76 if req.OperationValue(&rt) { 77 p.telemetryValue = fmt.Sprintf("%s %s", string(rt), p.telemetryValue) 78 } 79 req.Request.Header.Set(HeaderUserAgent, p.telemetryValue) 80 return req.Next() 81} 82 83// NOTE: the ONLY function that should write to this variable is this func 84var platformInfo = func() string { 85 operatingSystem := runtime.GOOS // Default OS string 86 switch operatingSystem { 87 case "windows": 88 operatingSystem = os.Getenv("OS") // Get more specific OS information 89 case "linux": // accept default OS info 90 case "freebsd": // accept default OS info 91 } 92 return fmt.Sprintf("(%s; %s)", runtime.Version(), operatingSystem) 93}() 94 95// used for adding per-request telemetry 96type requestTelemetry string 97