subtypes,handlers: add runtime trace regions (#4060)
* subtypes,handlers: add runtime trace regions The subtype.Filterable and handlers.ProtoToStruct functions are costly and worth measuring whenever runtime tracing is in use. This has almost no cost when tracing is not in use, so there's little harm in having them in place. * testing: Add TRACING.md TRACING.md contains information about how to perform Go runtime tracing of the Boundary application.
This commit is contained in:
1 parent
18729721a1
commit
a89573b35f
21 files changed
+102
-56
No files matched your search
@@ -187,7 +187,7 @@ func (s Service) ListAccounts(ctx context.Context, req *pbs.ListAccountsRequest)
|
||||
|
||||
// This comes last so that we can use item fields in the filter after
|
||||
// the allowed fields are populated above
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ func (s Service) ListAuthMethods(ctx context.Context, req *pbs.ListAuthMethodsRe
|
||||
|
||||
// This comes last so that we can use item fields in the filter after
|
||||
// the allowed fields are populated above
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1387,7 +1387,7 @@ func (s Service) convertToAuthenticateResponse(ctx context.Context, req *pbs.Aut
|
||||
}, nil
|
||||
}
|
||||
|
||||
func transformAuthenticateRequestAttributes(msg proto.Message) error {
|
||||
func transformAuthenticateRequestAttributes(ctx context.Context, msg proto.Message) error {
|
||||
const op = "authmethod.transformAuthenticateRequestAttributes"
|
||||
authRequest, ok := msg.(*pbs.AuthenticateRequest)
|
||||
if !ok {
|
||||
@@ -1451,7 +1451,7 @@ func transformAuthenticateRequestAttributes(msg proto.Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func transformAuthenticateResponseAttributes(msg proto.Message) error {
|
||||
func transformAuthenticateResponseAttributes(ctx context.Context, msg proto.Message) error {
|
||||
const op = "authmethod.transformAuthenticateResponseAttributes"
|
||||
authResponse, ok := msg.(*pbs.AuthenticateResponse)
|
||||
if !ok {
|
||||
@@ -1468,22 +1468,22 @@ func transformAuthenticateResponseAttributes(msg proto.Message) error {
|
||||
// No transformation necessary
|
||||
newAttrs = attrs.Attributes
|
||||
case *pbs.AuthenticateResponse_AuthTokenResponse:
|
||||
newAttrs, err = handlers.ProtoToStruct(attrs.AuthTokenResponse)
|
||||
newAttrs, err = handlers.ProtoToStruct(ctx, attrs.AuthTokenResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *pbs.AuthenticateResponse_OidcAuthMethodAuthenticateStartResponse:
|
||||
newAttrs, err = handlers.ProtoToStruct(attrs.OidcAuthMethodAuthenticateStartResponse)
|
||||
newAttrs, err = handlers.ProtoToStruct(ctx, attrs.OidcAuthMethodAuthenticateStartResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *pbs.AuthenticateResponse_OidcAuthMethodAuthenticateCallbackResponse:
|
||||
newAttrs, err = handlers.ProtoToStruct(attrs.OidcAuthMethodAuthenticateCallbackResponse)
|
||||
newAttrs, err = handlers.ProtoToStruct(ctx, attrs.OidcAuthMethodAuthenticateCallbackResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *pbs.AuthenticateResponse_OidcAuthMethodAuthenticateTokenResponse:
|
||||
newAttrs, err = handlers.ProtoToStruct(attrs.OidcAuthMethodAuthenticateTokenResponse)
|
||||
newAttrs, err = handlers.ProtoToStruct(ctx, attrs.OidcAuthMethodAuthenticateTokenResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package authmethods
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@@ -196,7 +197,7 @@ func TestTransformAuthenticateRequestAttributes(t *testing.T) {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
in := proto.Clone(c.input)
|
||||
require.NoError(t, transformAuthenticateRequestAttributes(in))
|
||||
require.NoError(t, transformAuthenticateRequestAttributes(context.Background(), in))
|
||||
require.Empty(t, cmp.Diff(c.expected, in, protocmp.Transform()))
|
||||
})
|
||||
}
|
||||
@@ -206,11 +207,11 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("not-an-authenticate-request", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pb.AuthMethod{}))
|
||||
require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pb.AuthMethod{}))
|
||||
})
|
||||
t.Run("invalid-auth-method-id", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "invalid",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{},
|
||||
@@ -219,7 +220,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) {
|
||||
})
|
||||
t.Run("invalid-oidc-command", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "invalid",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
@@ -229,7 +230,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) {
|
||||
})
|
||||
t.Run("invalid-password-attributes", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "apw_test",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
@@ -243,7 +244,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) {
|
||||
})
|
||||
t.Run("invalid-ldap-attributes", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amldap_test",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
Attributes: &structpb.Struct{
|
||||
@@ -257,7 +258,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) {
|
||||
})
|
||||
t.Run("invalid-oidc-start-attributes", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "start",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
@@ -272,7 +273,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) {
|
||||
})
|
||||
t.Run("invalid-oidc-token-attributes", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{
|
||||
require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: "amoidc_test",
|
||||
Command: "token",
|
||||
Attrs: &pbs.AuthenticateRequest_Attributes{
|
||||
@@ -421,7 +422,7 @@ func TestTransformAuthenticateResponseAttributes(t *testing.T) {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
in := proto.Clone(c.input)
|
||||
require.NoError(t, transformAuthenticateResponseAttributes(in))
|
||||
require.NoError(t, transformAuthenticateResponseAttributes(context.Background(), in))
|
||||
require.Empty(t, cmp.Diff(c.expected, in, protocmp.Transform()))
|
||||
})
|
||||
}
|
||||
@@ -431,6 +432,6 @@ func TestTransformAuthenticateResponseAttributesErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("not-an-authenticate-response", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Error(t, transformAuthenticateResponseAttributes(&pb.AuthMethod{}))
|
||||
require.Error(t, transformAuthenticateResponseAttributes(context.Background(), &pb.AuthMethod{}))
|
||||
})
|
||||
}
|
||||
+1
-1
@@ -177,7 +177,7 @@ func (s Service) ListCredentialLibraries(ctx context.Context, req *pbs.ListCrede
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ func (s Service) ListCredentials(ctx context.Context, req *pbs.ListCredentialsRe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ func (s Service) ListCredentialStores(ctx context.Context, req *pbs.ListCredenti
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ func (s Service) ListHostCatalogs(ctx context.Context, req *pbs.ListHostCatalogs
|
||||
|
||||
// This comes last so that we can use item fields in the filter after
|
||||
// the allowed fields are populated above
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ func (s Service) ListHostSetsWithOptions(ctx context.Context, req *pbs.ListHostS
|
||||
|
||||
// This comes last so that we can use item fields in the filter after
|
||||
// the allowed fields are populated above
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ func (s Service) ListHosts(ctx context.Context, req *pbs.ListHostsRequest) (*pbs
|
||||
|
||||
// This comes last so that we can use item fields in the filter after
|
||||
// the allowed fields are populated above
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ func (s Service) ListManagedGroups(ctx context.Context, req *pbs.ListManagedGrou
|
||||
|
||||
// This comes last so that we can use item fields in the filter after
|
||||
// the allowed fields are populated above
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
func TestOutgoingSplitCookie(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
attrs, err := ProtoToStruct(&pba.AuthToken{Token: "t_abc_1234567890"})
|
||||
attrs, err := ProtoToStruct(context.Background(), &pba.AuthToken{Token: "t_abc_1234567890"})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, OutgoingResponseFilter(context.Background(), rec, &pbs.AuthenticateResponse{Attrs: &pbs.AuthenticateResponse_Attributes{Attributes: attrs}, Type: "cookie"}))
|
||||
assert.ElementsMatch(t, rec.Result().Cookies(), []*http.Cookie{
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime/trace"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
@@ -30,7 +33,8 @@ func StructToProto(fields *structpb.Struct, p proto.Message, opt ...Option) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func ProtoToStruct(p proto.Message) (*structpb.Struct, error) {
|
||||
func ProtoToStruct(ctx context.Context, p proto.Message) (*structpb.Struct, error) {
|
||||
defer trace.StartRegion(ctx, "subtypes.ProtoToStruct").End()
|
||||
js, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
structpb "github.com/golang/protobuf/ptypes/struct"
|
||||
@@ -49,7 +50,7 @@ func TestStructToProtoToStruct(t *testing.T) {
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
st, err := ProtoToStruct(tc.pb)
|
||||
st, err := ProtoToStruct(context.Background(), tc.pb)
|
||||
require.NoError(t, err)
|
||||
|
||||
wantStruct := &structpb.Struct{}
|
||||
|
||||
@@ -104,6 +104,7 @@ func dynamicToSessionCredential(ctx context.Context, cred credential.Dynamic) (*
|
||||
switch c := cred.(type) {
|
||||
case credential.UsernamePassword:
|
||||
credData, err = handlers.ProtoToStruct(
|
||||
ctx,
|
||||
&pb.UsernamePasswordCredential{
|
||||
Username: c.Username(),
|
||||
Password: string(c.Password()),
|
||||
@@ -115,6 +116,7 @@ func dynamicToSessionCredential(ctx context.Context, cred credential.Dynamic) (*
|
||||
|
||||
case credential.SshPrivateKey:
|
||||
credData, err = handlers.ProtoToStruct(
|
||||
ctx,
|
||||
&pb.SshPrivateKeyCredential{
|
||||
Username: c.Username(),
|
||||
PrivateKey: string(c.PrivateKey()),
|
||||
@@ -196,6 +198,7 @@ func staticToSessionCredential(ctx context.Context, cred credential.Static) (*pb
|
||||
var err error
|
||||
credType = string(globals.UsernamePasswordCredentialType)
|
||||
credData, err = handlers.ProtoToStruct(
|
||||
ctx,
|
||||
&pb.UsernamePasswordCredential{
|
||||
Username: c.GetUsername(),
|
||||
Password: string(c.GetPassword()),
|
||||
@@ -213,6 +216,7 @@ func staticToSessionCredential(ctx context.Context, cred credential.Static) (*pb
|
||||
var err error
|
||||
credType = string(globals.SshPrivateKeyCredentialType)
|
||||
credData, err = handlers.ProtoToStruct(
|
||||
ctx,
|
||||
&pb.SshPrivateKeyCredential{
|
||||
Username: c.GetUsername(),
|
||||
PrivateKey: string(c.GetPrivateKey()),
|
||||
|
||||
@@ -258,7 +258,7 @@ func (s Service) ListTargets(ctx context.Context, req *pbs.ListTargetsRequest) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filterable, err := subtypes.Filterable(item)
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
package subtypes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime/trace"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
@@ -56,7 +58,7 @@ func convertAttributesToSubtype(msg proto.Message, st globals.Subtype) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertAttributesToDefault(msg proto.Message, st globals.Subtype) error {
|
||||
func convertAttributesToDefault(ctx context.Context, msg proto.Message, st globals.Subtype) error {
|
||||
r := msg.ProtoReflect()
|
||||
d := r.Descriptor()
|
||||
|
||||
@@ -86,7 +88,7 @@ func convertAttributesToDefault(msg proto.Message, st globals.Subtype) error {
|
||||
if !ok {
|
||||
return fmt.Errorf("found subtype attribute field that is not proto.Message: %s %s", d.FullName(), stAttrField.FullName())
|
||||
}
|
||||
defaultAttrs, err := handlers.ProtoToStruct(stAttrs)
|
||||
defaultAttrs, err := handlers.ProtoToStruct(ctx, stAttrs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -113,7 +115,8 @@ func convertAttributesToDefault(msg proto.Message, st globals.Subtype) error {
|
||||
//
|
||||
// If the message does not conform to this structure,
|
||||
// the original message is returned.
|
||||
func Filterable(item proto.Message) (proto.Message, error) {
|
||||
func Filterable(ctx context.Context, item proto.Message) (proto.Message, error) {
|
||||
defer trace.StartRegion(ctx, "subtypes.Filterable").End()
|
||||
clone := proto.Clone(item)
|
||||
r := clone.ProtoReflect()
|
||||
|
||||
@@ -138,13 +141,13 @@ func Filterable(item proto.Message) (proto.Message, error) {
|
||||
}
|
||||
|
||||
attr = r.Get(oneofField).Message().Interface()
|
||||
pbAttrs, err = handlers.ProtoToStruct(attr)
|
||||
pbAttrs, err = handlers.ProtoToStruct(ctx, attr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.Set(defaultAttrField, protoreflect.ValueOfMessage(pbAttrs.ProtoReflect()))
|
||||
f, err := handlers.ProtoToStruct(r.Interface())
|
||||
f, err := handlers.ProtoToStruct(ctx, r.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package subtypes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@@ -99,7 +100,7 @@ func TestFilterable(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got, err := Filterable(tc.item)
|
||||
got, err := Filterable(context.Background(), tc.item)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, cmp.Diff(got, tc.want, protocmp.Transform()))
|
||||
})
|
||||
|
||||
@@ -132,7 +132,7 @@ func transformRequestAttributes(req proto.Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func transformResponseItemAttributes(item proto.Message) error {
|
||||
func transformResponseItemAttributes(ctx context.Context, item proto.Message) error {
|
||||
r := item.ProtoReflect()
|
||||
desc := r.Descriptor()
|
||||
|
||||
@@ -154,13 +154,13 @@ func transformResponseItemAttributes(item proto.Message) error {
|
||||
}
|
||||
|
||||
st := globals.Subtype(item.ProtoReflect().Get(typeField).String())
|
||||
return convertAttributesToDefault(item, st)
|
||||
return convertAttributesToDefault(ctx, item, st)
|
||||
}
|
||||
|
||||
func transformRequest(msg proto.Message) error {
|
||||
func transformRequest(ctx context.Context, msg proto.Message) error {
|
||||
fqn := msg.ProtoReflect().Descriptor().FullName()
|
||||
if fn, ok := globalTransformationRegistry.requestTransformationFuncs[fqn]; ok {
|
||||
return fn(msg)
|
||||
return fn(ctx, msg)
|
||||
}
|
||||
return transformRequestAttributes(msg)
|
||||
}
|
||||
@@ -195,7 +195,7 @@ func transformRequest(msg proto.Message) error {
|
||||
// // other subtype attributes types
|
||||
// }
|
||||
// }
|
||||
func transformResponseAttributes(res proto.Message) error {
|
||||
func transformResponseAttributes(ctx context.Context, res proto.Message) error {
|
||||
r := res.ProtoReflect()
|
||||
fields := r.Descriptor().Fields()
|
||||
|
||||
@@ -208,7 +208,7 @@ func transformResponseAttributes(res proto.Message) error {
|
||||
}
|
||||
|
||||
item := r.Get(itemField).Message().Interface()
|
||||
return transformResponseItemAttributes(item)
|
||||
return transformResponseItemAttributes(ctx, item)
|
||||
case itemsField != nil:
|
||||
if !itemsField.IsList() {
|
||||
return nil
|
||||
@@ -217,7 +217,7 @@ func transformResponseAttributes(res proto.Message) error {
|
||||
|
||||
for i := 0; i < items.Len(); i++ {
|
||||
item := items.Get(i).Message().Interface()
|
||||
if err := transformResponseItemAttributes(item); err != nil {
|
||||
if err := transformResponseItemAttributes(ctx, item); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -225,12 +225,12 @@ func transformResponseAttributes(res proto.Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func transformResponse(msg proto.Message) error {
|
||||
func transformResponse(ctx context.Context, msg proto.Message) error {
|
||||
fqn := msg.ProtoReflect().Descriptor().FullName()
|
||||
if fn, ok := globalTransformationRegistry.responseTransformationFuncs[fqn]; ok {
|
||||
return fn(msg)
|
||||
return fn(ctx, msg)
|
||||
}
|
||||
return transformResponseAttributes(msg)
|
||||
return transformResponseAttributes(ctx, msg)
|
||||
}
|
||||
|
||||
// AttributeTransformerInterceptor is a grpc server interceptor that will
|
||||
@@ -278,11 +278,11 @@ func transformResponse(msg proto.Message) error {
|
||||
// This request will be transformed into:
|
||||
//
|
||||
// type:"password" password_attributes:{login_name:"tim"}
|
||||
func AttributeTransformerInterceptor(_ context.Context) grpc.UnaryServerInterceptor {
|
||||
func AttributeTransformerInterceptor(ctx context.Context) grpc.UnaryServerInterceptor {
|
||||
const op = "subtypes.AttributeTransformInterceptor"
|
||||
return func(interceptorCtx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||
if reqMsg, ok := req.(proto.Message); ok {
|
||||
if err := transformRequest(reqMsg); err != nil {
|
||||
if err := transformRequest(ctx, reqMsg); err != nil {
|
||||
fieldErrs := map[string]string{
|
||||
"attributes": "Attribute fields do not match the expected format.",
|
||||
}
|
||||
@@ -299,7 +299,7 @@ func AttributeTransformerInterceptor(_ context.Context) grpc.UnaryServerIntercep
|
||||
res, handlerErr := handler(interceptorCtx, req)
|
||||
|
||||
if res, ok := res.(proto.Message); ok {
|
||||
if err := transformResponse(res); err != nil {
|
||||
if err := transformResponse(ctx, res); err != nil {
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "failed building attribute struct: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package subtypes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@@ -304,7 +305,7 @@ func TestTransformRequestAttributes(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := transformRequest(tc.req)
|
||||
err := transformRequest(context.Background(), tc.req)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, cmp.Diff(tc.req, tc.expected, protocmp.Transform()))
|
||||
})
|
||||
@@ -588,7 +589,7 @@ func TestTransformResponseAttributes(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := transformResponse(tc.resp)
|
||||
err := transformResponse(context.Background(), tc.resp)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, cmp.Diff(tc.resp, tc.expected, protocmp.Transform()))
|
||||
})
|
||||
@@ -598,7 +599,7 @@ func TestTransformResponseAttributes(t *testing.T) {
|
||||
func TestCustomTransformRequest(t *testing.T) {
|
||||
RegisterRequestTransformationFunc(
|
||||
&attribute.TestCustomTransformation{},
|
||||
func(m proto.Message) error {
|
||||
func(_ context.Context, m proto.Message) error {
|
||||
msg, ok := m.(*attribute.TestCustomTransformation)
|
||||
require.True(t, ok, "wrong message passed to request transformation callback")
|
||||
if msg.SomeRandomId == "some_random_id" && msg.SecondaryId == "secondary_id" {
|
||||
@@ -634,7 +635,7 @@ func TestCustomTransformRequest(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
err := transformRequest(request)
|
||||
err := transformRequest(context.Background(), request)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, cmp.Diff(request, expected, protocmp.Transform()))
|
||||
}
|
||||
@@ -642,11 +643,11 @@ func TestCustomTransformRequest(t *testing.T) {
|
||||
func TestCustomTransformResponse(t *testing.T) {
|
||||
RegisterResponseTransformationFunc(
|
||||
&attribute.TestCustomTransformation{},
|
||||
func(m proto.Message) error {
|
||||
func(_ context.Context, m proto.Message) error {
|
||||
msg, ok := m.(*attribute.TestCustomTransformation)
|
||||
require.True(t, ok, "wrong message passed to response transformation callback")
|
||||
if msg.SomeRandomId == "some_random_id" && msg.SecondaryId == "secondary_id" {
|
||||
newAttrs, err := handlers.ProtoToStruct(msg.GetSubResourceAttributes())
|
||||
newAttrs, err := handlers.ProtoToStruct(context.Background(), msg.GetSubResourceAttributes())
|
||||
require.NoError(t, err)
|
||||
msg.Attrs = &attribute.TestCustomTransformation_Attributes{
|
||||
Attributes: newAttrs,
|
||||
@@ -677,7 +678,7 @@ func TestCustomTransformResponse(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
err := transformResponse(response)
|
||||
err := transformResponse(context.Background(), response)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, cmp.Diff(response, expected, protocmp.Transform()))
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func (r *transformationRegistry) registerResponseTransformationFunc(ctx context.
|
||||
|
||||
// TransformationFunc defines the signature used to transform
|
||||
// protobuf message attributes. The proto.Message is mutated in place.
|
||||
type TransformationFunc func(proto.Message) error
|
||||
type TransformationFunc func(context.Context, proto.Message) error
|
||||
|
||||
// RegisterRequestTransformationFunc registers a transformation function for
|
||||
// the provided message. The message should be used as a request parameter to
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Tracing in Boundary
|
||||
|
||||
Boundary includes a small number of runtime tracing user regions, which can be used to see where Boundary spends its time during execution.
|
||||
To create a trace, we first need to expose the pprof endpoint. It is disabled by default. Exposing the pprof endpoint is as simple as importing the correct package anywhere in Boundary:
|
||||
|
||||
```go
|
||||
package anything
|
||||
|
||||
import (
|
||||
_ "net/http/pprof"
|
||||
)
|
||||
```
|
||||
|
||||
This will create a new HTTP endpoint on `localhost:6060` of the running binary. As such, it's only accessible to the users on the same machine.
|
||||
Remember to remove this import again once you're done testing.
|
||||
|
||||
To create a trace, one can use any tool that allows creating HTTP requests, e.g. `curl`. To create a 3 second trace:
|
||||
|
||||
```
|
||||
$ curl -o trace.out http://localhost:6060/debug/pprof/trace?seconds=3
|
||||
```
|
||||
|
||||
Traces are most interesting if they contain some request handling, so it is recommended to prepare some HTTP requests that trigger the behavior you want to understand that you can run while the trace is being collected.
|
||||
|
||||
Once you have a trace, you can view it using the `gotraceui` tool. See https://github.com/dominikh/gotraceui/ for installation instructions,
|
||||
but for both Windows and Mac it's as simple as:
|
||||
|
||||
```
|
||||
$ go run honnef.co/go/gotraceui/cmd/gotraceui@master trace.out
|
||||
```
|
||||
|
||||
Reference in new issue
Block a user