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

Flow complete fix #9

Merged
merged 3 commits into from
Jan 9, 2025
Merged

Flow complete fix #9

merged 3 commits into from
Jan 9, 2025

Conversation

andreibratu
Copy link
Contributor

@andreibratu andreibratu commented Jan 6, 2025

  • Simplified the code that kept track of the trace built by decorators - instead of relying on OT's context, we are only peeking at the status of the ancestor on the level above -
  • The exporter correctly completes flow traces - instead of waiting for the program exit to upload the spans, I am attaching a new span attribute instructing the exporter which spans' logs should be uploaded before completing the flow log. To make this work, the processor keeps a running list of spans as they start, which belong in a particular trace. The list is attached to the flow span during the onEnd signal. The spans created by utilities will no longer have a UUIDv4 name but be named after the log type they carry, e.g., humanloop.prompt or humanloop.flow. This is also more dogmatic with how OT does things

@olehvell-h olehvell-h self-requested a review January 7, 2025 09:18
@@ -69,6 +72,19 @@ export class HumanloopSpanExporter implements SpanExporter {
await this.shutdown();
}

private completeFlowLog(spanId: string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

this needs more comments and a docstring.
this is doing a lot - mutating this.prerequisite's values, conditionally doing many things (the delete and the update). hard to follow/check if there are bugs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack fixed

*/
export function generateSpanId(): string {
return uuidv4();
return span.name.startsWith("humanloop.");
Copy link
Contributor

Choose a reason for hiding this comment

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

should be a const

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

}

async forceFlush(): Promise<void> {}

onStart(span: Span, _: Context): void {
const spanId = span.spanContext().spanId;
const parentSpanId = span.parentSpanId;
if (span.name === "humanloop.flow") {
Copy link
Contributor

Choose a reason for hiding this comment

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

"humanloop.flow" should be a const

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

// Humanloop parent span owning them
if (span.name === "humanloop.flow") {
Copy link
Contributor

Choose a reason for hiding this comment

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

should be a const

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

@@ -39,30 +38,9 @@ export function flowUtilityFactory<I, M, O>(
const parentSpanContextKey = createContextKey(HUMANLOOP_PARENT_SPAN_CTX_KEY);
const flowMetadataKey = createContextKey(HUMANLOOP_TRACE_FLOW_CTX_KEY);
// @ts-ignore
return opentelemetryTracer.startActiveSpan(generateSpanId(), async (span) => {
return opentelemetryTracer.startActiveSpan("humanloop.flow", async (span) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

do these not need to be unique?

(should be a const)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've realized it's not necessary. The name is supposed to hint at the type of span you're looking at, which I'm leveraging in the processor-exporter to complete the trace.

https://opentelemetry.io/docs/specs/semconv/http/http-spans/#name

@@ -61,28 +60,9 @@ export function promptUtilityFactory<I, M, O>(
const flowMetadataKey = createContextKey(HUMANLOOP_TRACE_FLOW_CTX_KEY);

// @ts-ignore
return opentelemetryTracer.startActiveSpan(generateSpanId(), async (span) => {
return opentelemetryTracer.startActiveSpan("humanloop.prompt", async (span) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

humanloop.prompt should be a const

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

output = await func(inputs, messages);
} catch (err: any) {
console.error(`Error calling ${func.name}:`, err);
// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

what's the tsignore doing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

seems to be a leftover, removed

*
* @param spanId - The ID of the span that has been uploaded.
*/
private notifySpanUploaded(spanId: string) {

Choose a reason for hiding this comment

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

noob question - why notifySpanUploaded and not e.g. markSpanCompleted. Is notify OT jargon?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fair point will change - no OT jargon, just bad taste on my side

if (span.name === HUMANLOOP_FLOW_SPAN_NAME) {
this.prerequisites.set(spanId, []);
}
if (parentSpanId !== undefined && isHumanloopSpan(span)) {

Choose a reason for hiding this comment

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

noob question - (parentSpanId !== undefined && isHumanloopSpan(span)) this is to check if it's a span from flow child ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep - i am building a flat list of all logs found inside a trace. this list is passed as an attribute on the flow log span to the expoter. when they're all uploaded, the flow log is also marked as complete

Copy link

@olehvell-h olehvell-h left a comment

Choose a reason for hiding this comment

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

Looks good... to the extent of my OT knowledge 😅

Side point: We as a team (and I personally), need a bit of learning on OT. It takes mental energy to understand OT-specific jargon and details before focusing on code-related matters.

Thank you for writing PR description and " Please assign yourself as a reviewer if you have the time." - like this bit

@andreibratu andreibratu merged commit f0bf780 into master Jan 9, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants