Skip to content
This repository was archived by the owner on May 18, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions .circleci/config.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
# This file controls who is tagged for review for any given pull request.

# For anything not explicitly taken by someone else:
* @honeycombio/collection-team
* @jayanth-tatina-groww @souravde
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ updates:
labels:
- "type: dependencies"
reviewers:
- "honeycombio/collection-team"
- "honeycombio/pipeline"
commit-message:
prefix: "maint"
include: "scope"
2 changes: 2 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ changelog:
- title: 🛠 Maintenance
labels:
- "type: maintenance"
- "type: dependencies"
- "type: documentation"
- title: 🤷 Other Changes
labels:
- "*"
15 changes: 0 additions & 15 deletions .github/workflows/add-to-project-v2.yml

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
unit-tests.xml

.idea
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Husky Changelog

## 0.23.1 2023-12-08

- fix: bug where we could error after writing a status code (#224) | [Tyler Helmuth](https://github.com/TylerHelmuth)
- maint: add deps and docs to maintenance in release (#223) | [Jamie Danielson](https://github.com/JamieDanielson)
- maint: add extra detail to release doc (#222) | [Jamie Danielson](https://github.com/JamieDanielson)

## 0.23.0 2023-12-08

- feat: Add public functions for handling OTLP HTTP responses (#219) | [Tyler Helmuth](https://github.com/TylerHelmuth)
- maint: update codeowners (#220) | [Tyler Helmuth](https://github.com/TylerHelmuth)
- maint(deps): bump google.golang.org/grpc from 1.58.3 to 1.59.0 (#218)
- maint(deps): bump github.com/klauspost/compress from 1.17.2 to 1.17.4 (#217)
- maint(deps): bump google.golang.org/grpc from 1.58.2 to 1.58.3 (#215)
- maint(deps): bump golang.org/x/net from 0.12.0 to 0.17.0 (#214)
- maint: bump github.com/klauspost/compress from 1.16.7 to 1.17.2 (#213) | [Tyler Helmuth](https://github.com/TylerHelmuth)
- maint(deps): bump google.golang.org/grpc from 1.56.1 to 1.58.2 (#210)
- maint(deps): bump github.com/klauspost/compress from 1.16.5 to 1.16.7 (#204)
- maint(deps): bump google.golang.org/grpc from 1.55.0 to 1.56.1 (#202)
- maint(deps): bump google.golang.org/protobuf from 1.30.0 to 1.31.0 (#203)
- maint(deps): bump google.golang.org/grpc from 1.54.0 to 1.55.0 (#200)
- maint(deps): bump github.com/stretchr/testify from 1.8.2 to 1.8.4 (#199)


## 0.22.4 2023-05-16

fix: Send the values not the Values in exception details (#197) | [Kent Quirk](https://github.com/kentquirk)
Expand Down
17 changes: 10 additions & 7 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Release Process

1. Update [Version.go](version.go) with new version
2. Add release entry to [changelog](./CHANGELOG.md). Consider using a command like so:
* `git log --pretty='%C(green)%d%Creset- %s | [%an](https://github.com/)'`
3. Open a PR with the above, and merge that into main
4. Create new tag on merged commit with the new version (e.g. `v1.4.1`)
5. Push the tag upstream (this will kick off the release pipeline in CI)
6. Copy change log entry for newest version into draft GitHub release created as part of CI publish steps
- Update [`version.go`](version.go) with new version
- Add release entry to [changelog](./CHANGELOG.md). Consider using a command like so:
- `git log --pretty='%C(green)%d%Creset- %s | [%an](https://github.com/)'`
- Commit changes, push, and open a release preparation pull request for review.
- Once the pull request is merged, fetch the updated `main` branch.
- Apply a tag for the new version on the merged commit (e.g. `git tag -a v2.3.1 -m "v2.3.1"`)
- Push the tag upstream (this will kick off the release pipeline in CI) e.g. `git push origin v2.3.1`
- Ensure that there is a draft GitHub release created as part of CI publish steps
- Click "generate release notes" in github for full changelog notes and any new contributors
- Publish the github draft release
16 changes: 9 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
module github.com/honeycombio/husky

go 1.18
go 1.21

require (
github.com/json-iterator/go v1.1.12
github.com/klauspost/compress v1.16.7
github.com/klauspost/compress v1.17.4
github.com/stretchr/testify v1.8.4
go.opentelemetry.io/proto/otlp v0.19.0
google.golang.org/grpc v1.56.1
google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0
)

Expand All @@ -19,10 +19,12 @@ require (
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

Expand Down
34 changes: 21 additions & 13 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,25 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
github.com/honeycombio/opentelemetry-proto-go/otlp v0.19.0-compat h1:fMpIzVAl5C260HisnRWV//vfckZIC4qvn656M3VLLOY=
github.com/honeycombio/opentelemetry-proto-go/otlp v0.19.0-compat/go.mod h1:mC2aK20Z/exugKpqCgcpwEadiS0im8K6mZsD4Is/hCY=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
Expand All @@ -30,22 +33,27 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ=
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
121 changes: 121 additions & 0 deletions otlp/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"bytes"
"compress/gzip"
"context"
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"math"
"net/http"
Expand All @@ -13,8 +16,12 @@ import (

jsoniter "github.com/json-iterator/go"
"github.com/klauspost/compress/zstd"
collectorlogs "go.opentelemetry.io/proto/otlp/collector/logs/v1"
collectormetrics "go.opentelemetry.io/proto/otlp/collector/metrics/v1"
collectortrace "go.opentelemetry.io/proto/otlp/collector/trace/v1"
common "go.opentelemetry.io/proto/otlp/common/v1"
resource "go.opentelemetry.io/proto/otlp/resource/v1"
spb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
Expand Down Expand Up @@ -190,6 +197,61 @@ func GetRequestInfoFromHttpHeaders(header http.Header) RequestInfo {
}
}

// WriteOtlpHttpFailureResponse is a quick way to write an otlp response for an error.
// It calls WriteOtlpHttpResponse, using the error's HttpStatusCode and building a Status
// using the error's string.
func WriteOtlpHttpFailureResponse(w http.ResponseWriter, r *http.Request, err OTLPError) error {
return WriteOtlpHttpResponse(w, r, err.HTTPStatusCode, &spb.Status{Message: err.Error()})
}

// WriteOtlpHttpTraceSuccessResponse is a quick way to write an otlp success response for a trace request.
// It calls WriteOtlpHttpResponse, using the 200 status code and an empty ExportTraceServiceResponse
func WriteOtlpHttpTraceSuccessResponse(w http.ResponseWriter, r *http.Request) error {
return WriteOtlpHttpResponse(w, r, http.StatusOK, &collectortrace.ExportTraceServiceResponse{})
}

// WriteOtlpHttpMetricSuccessResponse is a quick way to write an otlp success response for a metric request.
// It calls WriteOtlpHttpResponse, using the 200 status code and an empty ExportMetricsServiceResponse
func WriteOtlpHttpMetricSuccessResponse(w http.ResponseWriter, r *http.Request) error {
return WriteOtlpHttpResponse(w, r, http.StatusOK, &collectormetrics.ExportMetricsServiceResponse{})
}

// WriteOtlpHttpLogSuccessResponse is a quick way to write an otlp success response for a trace request.
// It calls WriteOtlpHttpResponse, using the 200 status code and an empty ExportLogsServiceResponse
func WriteOtlpHttpLogSuccessResponse(w http.ResponseWriter, r *http.Request) error {
return WriteOtlpHttpResponse(w, r, http.StatusOK, &collectorlogs.ExportLogsServiceResponse{})
}

// WriteOtlpHttpResponse writes a compliant OTLP HTTP response to the given http.ResponseWriter
// based on the provided `contentType`. If an error occurs while marshalling to either json or proto it is returned
// before the http.ResponseWriter is updated. If an error occurs while writing to the http.ResponseWriter it is ignored.
func WriteOtlpHttpResponse(w http.ResponseWriter, r *http.Request, statusCode int, m proto.Message) error {
if r == nil {
return fmt.Errorf("nil Request")
}

contentType := r.Header.Get("Content-Type")
var body []byte
var err error
switch contentType {
case "application/json":
body, err = protojson.Marshal(m)
case "application/x-protobuf", "application/protobuf":
body, err = proto.Marshal(m)
default:
return ErrInvalidContentType
}
if err != nil {
return err
}

// At this point we're committed
w.Header().Set("Content-Type", contentType)
w.WriteHeader(statusCode)
_, _ = w.Write(body)
return nil
}

func getValueFromMetadata(md metadata.MD, key string) string {
if vals := md.Get(key); len(vals) > 0 {
return vals[0]
Expand Down Expand Up @@ -421,3 +483,62 @@ func parseOtlpRequestBody(body io.ReadCloser, contentType string, contentEncodin

return nil
}

// BytesToTraceID returns an ID suitable for use for spans and traces. Before
// encoding the bytes as a hex string, we want to handle cases where we are
// given 128-bit IDs with zero padding, e.g. 0000000000000000f798a1e7f33c8af6.
// There are many ways to achieve this, but careful benchmarking and testing
// showed the below as the most performant, avoiding memory allocations
// and the use of flexible but expensive library functions. As this is hot code,
// it seemed worthwhile to do it this way.
func BytesToTraceID(traceID []byte) string {
var encoded []byte
switch len(traceID) {
case traceIDLongLength: // 16 bytes, trim leading 8 bytes if all 0's
if shouldTrimTraceId(traceID) {
encoded = make([]byte, 16)
traceID = traceID[traceIDShortLength:]
} else {
encoded = make([]byte, 32)
}
hex.Encode(encoded, traceID)
case traceIDShortLength: // 8 bytes
encoded = make([]byte, 16)
hex.Encode(encoded, traceID)
case traceIDb64Length: // 24 bytes
// The spec says that traceID and spanID should be encoded as hex, but
// the protobuf system is interpreting them as b64, so we need to
// reverse them back to b64 which gives us the original hex.
encoded = make([]byte, base64.StdEncoding.EncodedLen(len(traceID)))
base64.StdEncoding.Encode(encoded, traceID)
default:
encoded = make([]byte, len(traceID)*2)
hex.Encode(encoded, traceID)
}
return string(encoded)
}

func BytesToSpanID(spanID []byte) string {
var encoded []byte
switch len(spanID) {
case spanIDb64Length: // 12 bytes
// The spec says that traceID and spanID should be encoded as hex, but
// the protobuf system is interpreting them as b64, so we need to
// reverse them back to b64 which gives us the original hex.
encoded = make([]byte, base64.StdEncoding.EncodedLen(len(spanID)))
base64.StdEncoding.Encode(encoded, spanID)
default:
encoded = make([]byte, len(spanID)*2)
hex.Encode(encoded, spanID)
}
return string(encoded)
}

func shouldTrimTraceId(traceID []byte) bool {
for i := 0; i < 8; i++ {
if traceID[i] != 0 {
return false
}
}
return true
}
Loading