wrapTransportWithTelemetryHeader adds telemetry headers to report command usage to an HTTP transport.
(transport http.RoundTripper, inv *serpent.Invocation)
| 1637 | // wrapTransportWithTelemetryHeader adds telemetry headers to report command usage |
| 1638 | // to an HTTP transport. |
| 1639 | func wrapTransportWithTelemetryHeader(transport http.RoundTripper, inv *serpent.Invocation) http.RoundTripper { |
| 1640 | var ( |
| 1641 | value string |
| 1642 | once sync.Once |
| 1643 | ) |
| 1644 | return roundTripper(func(req *http.Request) (*http.Response, error) { |
| 1645 | once.Do(func() { |
| 1646 | // We only want to compute this header once when a request |
| 1647 | // first goes out, hence the complexity with locking here. |
| 1648 | var topts []telemetry.Option |
| 1649 | for _, opt := range inv.Command.FullOptions() { |
| 1650 | if opt.ValueSource == serpent.ValueSourceNone || opt.ValueSource == serpent.ValueSourceDefault { |
| 1651 | continue |
| 1652 | } |
| 1653 | topts = append(topts, telemetry.Option{ |
| 1654 | Name: opt.Name, |
| 1655 | ValueSource: string(opt.ValueSource), |
| 1656 | }) |
| 1657 | } |
| 1658 | ti := telemetry.Invocation{ |
| 1659 | Command: inv.Command.FullName(), |
| 1660 | Options: topts, |
| 1661 | InvokedAt: time.Now(), |
| 1662 | } |
| 1663 | |
| 1664 | byt, err := json.Marshal(ti) |
| 1665 | if err != nil { |
| 1666 | // Should be impossible |
| 1667 | panic(err) |
| 1668 | } |
| 1669 | s := base64.StdEncoding.EncodeToString(byt) |
| 1670 | // Don't send the header if it's too long! |
| 1671 | if len(s) <= 4096 { |
| 1672 | value = s |
| 1673 | } |
| 1674 | }) |
| 1675 | if value != "" { |
| 1676 | req.Header.Add(codersdk.CLITelemetryHeader, value) |
| 1677 | } |
| 1678 | return transport.RoundTrip(req) |
| 1679 | }) |
| 1680 | } |
| 1681 | |
| 1682 | // wrapTransportWithUserAgentHeader sets a User-Agent header for all CLI requests |
| 1683 | // that includes the CLI version, os/arch, and the specific command being run. |