Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add otel instrumentation to logwriter #179

Merged
merged 1 commit into from
Feb 16, 2024

Conversation

obs-gh-alexlew
Copy link
Contributor

No description provided.

@obs-gh-alexlew
Copy link
Contributor Author

tried to run gofumpt locally but it just hung, not sure how to clear up the lint error

detector := lambdadetector.NewResourceDetector()
res, err := resource.New(ctx,
resource.WithDetectors(detector),
resource.WithAttributes(semconv.ServiceName("aws-sam-apps/subscriber")),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably come from the OTEL_SERVICE_NAME environment variable or be passed in as an argument, rather than hardcoded in package.

sdktrace.WithResource(res),
)
otel.SetTracerProvider(tracerProvider)
otelaws.AppendMiddlewares(&awsCfg.APIOptions)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure doing this here is a good idea. InitTracing is a singleton, you would never want to instantiate it twice. It should probably be wrapped in a sync.Once. On the other hand, you may very well want different AWS clients (e.g. one per region). It's odd that you must provide an aws.Config to even initialize tracing.

return tracer, nil
}

func Shutdown(ctx context.Context) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could change InitTracing from:

InitTracing(ctx context.Context, awsCfg *aws.Config) (trace.Tracer, error)

to

InitTracing(ctx context.Context) (trace.Tracer, func(context.Context) error)

The invocation would look like:

tracer, shutdownFn := InitTracing(ctx)
if tracer == nil {
   err := shutdownFn()
   panic(err)
}

defer shutdownFn()

By returning the shutdown callback you still have a mechanism by which to surface initialization errors, and you get rid of the tracerProvider global.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would I want to panic here vs. just returning an error from init? both ways the program's going to exit right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also the problem with the shutdown is that it needs to happen in the SIGTERM handler in the main fn instead. I could have a global variable that I assign the shutdown to in main.go but then the instrumentation code is leaking a bit.

*Handler
}

func (h *InstrumentedHandler) HandleSQS(ctx context.Context, request events.SQSEvent) (response events.SQSEventResponse, err error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uff, this one is rough. There's no instrumentation here :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah essentially all im trying to do here is replace h.HandleRequest with the instance for InstrumentedHandler vs. for the base handler unfortunately i think I need to redefine this function to make this happen? unless there's a way to re-define the exact same function but with InstrumentedHandler as the receiver. I looked online but couldn't find anything. Also I tested this without redefining it and it does fall back to the Handler's implementation of HandleRequest without instrumentation

handler lambda.Handler
logger logr.Logger
entrypoint handler.Mux
shutdownFn lambda.Option
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options []lambda.Option is less prescriptive.

err := tracerShutdownFn(ctx)
return fmt.Errorf("failed to initialize tracing: %w", err)
}
shutdownFn = subscriber.FormatLambdaShutdown(ctx)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like an excessively shallow function. You could inline it:

options = append(options, lambda.WithEnableSIGTERM(func() {
	logger.V(4).Info("SIGTERM received, running shutdown")
	err := shutdownFn(ctx)
	if err != nil {
		logger.V(4).Error(err, "tracer shutdown failed")
	}
	logger.V(4).Info("shutdown done running")
}))

"github.com/observeinc/aws-sam-apps/handler/subscriber"
)

type S3Queue struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is confusing. Is it S3, or is it a queue?!

propagator := propagation.NewCompositeTextMapPropagator(propagation.Baggage{}, propagation.TraceContext{})
ctx = propagator.Extract(ctx, req.TraceContext)
}
ctx, span := h.Tracer.Start(ctx, "HandleRequest", trace.WithAttributes(attribute.String("key1", "value1")))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key1, value1

)

type SQSMessageAttributesCarrier struct {
typesMessageAttributes map[string]types.MessageAttributeValue
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are different types on the outbound sqs message and inbound one. had to reimplement/copy the library to handle the type difference, the lib just uses types.MessageAttributeValue but if I try to use that as the type for HandleSQSRequest then the reflex muxer matching doesn't work

Client SQSClient
URL string
}

func (q *queueWrapper) Put(ctx context.Context, items ...any) error {
func (q *QueueWrapper) Put(ctx context.Context, items ...*Request) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you still need to change this from any? Looks like you no longer need to know anything about the payload.

"github.com/aws/aws-sdk-go-v2/service/sqs"
)

type SQSClient struct {
Copy link
Contributor

@jta jta Feb 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't strictly need a struct here. You can add a method to the function:

type SendMessageFunc func(context.Context, *sqs.SendMessageInput, ...func(*sqs.Options)) (*sqs.SendMessageOutput, error)

func (fn *SendMessageFunc)  SendMessage(ctx context.Context, params *sqs.SendMessageInput, optFns ...func(*sqs.Options)) (*sqs.SendMessageOutput, error) {
	return fn.SendMessageFunc(ctx, params, optFns...)
}

This is similar to what net/http does for HandlerFunc vs Handler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's c in the above example now that there's no struct?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

derp, I swapped c for fn in the receiver, but not in the body of the method.

@obs-gh-alexlew obs-gh-alexlew merged commit 3db4a4d into main Feb 16, 2024
14 checks passed
@obs-gh-alexlew obs-gh-alexlew deleted the alew/instrument-logwriter-otel-2 branch February 16, 2024 22:29
Copy link

🎉 This PR is included in version 1.7.0-beta.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Copy link

🎉 This PR is included in version 1.7.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants