-
Notifications
You must be signed in to change notification settings - Fork 199
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
Enable exporting spans to snowflake stage if a TruLensSnowflakeSpanExporter
is provided
#1708
Merged
Merged
Changes from 2 commits
Commits
Show all changes
74 commits
Select commit
Hold shift + click to select a range
929187f
move things out of app.py
sfc-gh-gtokernliang b4d2c84
add tests
sfc-gh-gtokernliang f112f38
update golden
sfc-gh-gtokernliang 197cd0a
update app.py
sfc-gh-gtokernliang 062d197
update golden
sfc-gh-gtokernliang 1cc2a95
update golden
sfc-gh-gtokernliang dfc3fa5
move main output
sfc-gh-gtokernliang 95f250c
PR feedback
sfc-gh-gtokernliang 788f945
not sure why this is needed
sfc-gh-gtokernliang ef17076
add tests
sfc-gh-gtokernliang 2c9d9bb
update golden
sfc-gh-gtokernliang 85cbdc6
update test
sfc-gh-gtokernliang 65544c9
update golden
sfc-gh-gtokernliang 9b9644b
save
sfc-gh-gtokernliang 02855f9
draft
sfc-gh-gtokernliang d9a4694
save
sfc-gh-gtokernliang 5c939ac
add back debugger
sfc-gh-gtokernliang d025a07
update notebook
sfc-gh-gtokernliang bcd677f
fix
sfc-gh-gtokernliang 8456019
update semcov
sfc-gh-gtokernliang d2d2361
remove artifacts
sfc-gh-gtokernliang b3ff929
remove span_types from SpanAttributes
sfc-gh-gtokernliang d4603b1
modified it to accept multiple tokens
sfc-gh-gtokernliang cbeb5a4
fix bug with multiple func calls
sfc-gh-gtokernliang 1846dba
PR feedback
sfc-gh-gtokernliang eab220e
add tests
sfc-gh-gtokernliang 093f8ad
add tests
sfc-gh-gtokernliang 0236798
nits
sfc-gh-gtokernliang 7d0e800
pr feedback
sfc-gh-gtokernliang a8e9084
update golden
sfc-gh-gtokernliang 5d35d11
update test file
sfc-gh-gtokernliang af18dde
update golden
sfc-gh-gtokernliang f3c9e22
PR feedback
sfc-gh-gtokernliang e94147f
draft
sfc-gh-gtokernliang 2a74796
remove file
sfc-gh-gtokernliang fd645d1
don't compress
sfc-gh-gtokernliang 258abd2
remove print
sfc-gh-gtokernliang 28cee08
update golden
sfc-gh-gtokernliang 7dc4a1c
added comments
sfc-gh-gtokernliang d8422ad
gzip
sfc-gh-gtokernliang 09f69ca
update
sfc-gh-gtokernliang ab0bb6a
update protobuf
sfc-gh-gtokernliang 9e50f2c
Merge branch 'main' of github.com:truera/trulens into garett/SNOW-187…
sfc-gh-gtokernliang 21f9b72
pr feedback
sfc-gh-gtokernliang 37b6dcc
is this where I add it?
sfc-gh-gtokernliang e23b2fc
maybe here?
sfc-gh-gtokernliang af90428
undo migration
sfc-gh-gtokernliang 0fce605
update
sfc-gh-gtokernliang 0422373
save
sfc-gh-gtokernliang 3083dd1
improvements
sfc-gh-gtokernliang 18d1094
feedback
sfc-gh-gtokernliang 910265b
remove app.py
sfc-gh-gtokernliang 9280281
remove instruments.py
sfc-gh-gtokernliang 6ca1f3c
remove unused
sfc-gh-gtokernliang a91b0eb
update
sfc-gh-gtokernliang b3c5eca
Merge branch 'main' of github.com:truera/trulens into garett/SNOW-187…
sfc-gh-gtokernliang bd3fb50
update
sfc-gh-gtokernliang 881c68d
update
sfc-gh-gtokernliang 5fff6fc
extract
sfc-gh-gtokernliang 2d7b6a0
Merge branch 'garett/add-utils' of github.com:truera/trulens into gar…
sfc-gh-gtokernliang 8bae5fb
nits
sfc-gh-gtokernliang c11b1c9
update golden
sfc-gh-gtokernliang 5a55584
Merge branch 'garett/add-utils' of github.com:truera/trulens into gar…
sfc-gh-gtokernliang 61d87a8
pr feedback
sfc-gh-gtokernliang 8824794
Merge branch 'garett/add-utils' of github.com:truera/trulens into gar…
sfc-gh-gtokernliang a9f0537
pr feedback
sfc-gh-gtokernliang 9f4c8a3
Merge branch 'main' of github.com:truera/trulens into garett/SNOW-187…
sfc-gh-gtokernliang f46af3c
save
sfc-gh-gtokernliang 2903b52
draft
sfc-gh-gtokernliang 1a5d455
comments
sfc-gh-gtokernliang 0353258
PR feedback
sfc-gh-gtokernliang c28e10d
pr feedback
sfc-gh-gtokernliang 1c1d718
update golden
sfc-gh-gtokernliang 4e27038
PR feedback
sfc-gh-gtokernliang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
src/core/trulens/experimental/otel_tracing/core/exporter/connector.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import logging | ||
from typing import Sequence | ||
|
||
from opentelemetry.sdk.trace import ReadableSpan | ||
from opentelemetry.sdk.trace.export import SpanExporter | ||
from opentelemetry.sdk.trace.export import SpanExportResult | ||
from trulens.core.database import connector as core_connector | ||
from trulens.experimental.otel_tracing.core.exporter.utils import ( | ||
check_if_trulens_span, | ||
) | ||
from trulens.experimental.otel_tracing.core.exporter.utils import ( | ||
construct_event, | ||
) | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class TruLensOTELSpanExporter(SpanExporter): | ||
""" | ||
Implementation of `SpanExporter` that flushes the spans in the TruLens session to the connector. | ||
""" | ||
|
||
connector: core_connector.DBConnector | ||
""" | ||
The database connector used to export the spans. | ||
""" | ||
|
||
def __init__(self, connector: core_connector.DBConnector): | ||
self.connector = connector | ||
|
||
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult: | ||
trulens_spans = list(filter(check_if_trulens_span, spans)) | ||
|
||
try: | ||
events = list(map(construct_event, trulens_spans)) | ||
self.connector.add_events(events) | ||
|
||
except Exception as e: | ||
logger.error( | ||
f"Error exporting spans to the database: {e}", | ||
) | ||
return SpanExportResult.FAILURE | ||
|
||
return SpanExportResult.SUCCESS |
107 changes: 107 additions & 0 deletions
107
src/core/trulens/experimental/otel_tracing/core/exporter/snowflake.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import logging | ||
import os | ||
import tempfile | ||
from typing import Sequence | ||
|
||
from opentelemetry.sdk.trace import ReadableSpan | ||
from opentelemetry.sdk.trace.export import SpanExporter | ||
from opentelemetry.sdk.trace.export import SpanExportResult | ||
from trulens.connectors.snowflake import SnowflakeConnector | ||
from trulens.core.database import connector as core_connector | ||
from trulens.experimental.otel_tracing.core.exporter.utils import ( | ||
check_if_trulens_span, | ||
) | ||
from trulens.experimental.otel_tracing.core.exporter.utils import ( | ||
convert_readable_span_to_proto, | ||
) | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class TruLensSnowflakeSpanExporter(SpanExporter): | ||
""" | ||
Implementation of `SpanExporter` that flushes the spans in the TruLens session to a Snowflake Stage. | ||
""" | ||
|
||
connector: core_connector.DBConnector | ||
""" | ||
The database connector used to export the spans. | ||
""" | ||
|
||
def __init__(self, connector: core_connector.DBConnector): | ||
self.connector = connector | ||
|
||
def _export_to_snowflake_stage( | ||
self, spans: Sequence[ReadableSpan] | ||
) -> SpanExportResult: | ||
""" | ||
Exports a list of spans to a Snowflake stage as a protobuf file. | ||
This function performs the following steps: | ||
1. Writes the provided spans to a temporary protobuf file. | ||
2. Creates a Snowflake stage if it does not already exist. | ||
3. Uploads the temporary protobuf file to the Snowflake stage. | ||
4. Removes the temporary protobuf file. | ||
Args: | ||
spans (Sequence[ReadableSpan]): A sequence of spans to be exported. | ||
Returns: | ||
SpanExportResult: The result of the export operation, either SUCCESS or FAILURE. | ||
""" | ||
if not isinstance(self.connector, SnowflakeConnector): | ||
return SpanExportResult.FAILURE | ||
|
||
# Avoid uploading empty files to the stage | ||
if not spans: | ||
return SpanExportResult.SUCCESS | ||
|
||
snowpark_session = self.connector.snowpark_session | ||
tmp_file_path = "" | ||
|
||
try: | ||
with tempfile.NamedTemporaryFile( | ||
delete=False, suffix=".pb", mode="wb" | ||
) as tmp_file: | ||
tmp_file_path = tmp_file.name | ||
logger.debug( | ||
f"Writing spans to the protobuf file: {tmp_file_path}" | ||
) | ||
|
||
for span in spans: | ||
span_proto = convert_readable_span_to_proto(span) | ||
tmp_file.write(span_proto.SerializeToString()) | ||
logger.debug( | ||
f"Spans written to the protobuf file: {tmp_file_path}" | ||
) | ||
except Exception as e: | ||
logger.error(f"Error writing spans to the protobuf file: {e}") | ||
return SpanExportResult.FAILURE | ||
|
||
try: | ||
logger.debug("Uploading file to Snowflake stage") | ||
|
||
logger.debug("Creating Snowflake stage if it does not exist") | ||
snowpark_session.sql( | ||
"CREATE TEMP STAGE IF NOT EXISTS trulens_spans" | ||
).collect() | ||
|
||
logger.debug("Uploading the protobuf file to the stage") | ||
snowpark_session.sql( | ||
f"PUT file://{tmp_file_path} @trulens_spans" | ||
).collect() | ||
|
||
except Exception as e: | ||
logger.error(f"Error uploading the protobuf file to the stage: {e}") | ||
return SpanExportResult.FAILURE | ||
|
||
try: | ||
logger.debug("Removing the temporary protobuf file") | ||
os.remove(tmp_file_path) | ||
except Exception as e: | ||
# Not returning failure here since the export was technically a success | ||
logger.error(f"Error removing the temporary protobuf file: {e}") | ||
|
||
return SpanExportResult.SUCCESS | ||
|
||
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult: | ||
trulens_spans = list(filter(check_if_trulens_span, spans)) | ||
|
||
return self._export_to_snowflake_stage(trulens_spans) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you do the same as RECORD_ID For the other attributes? Since I guess the APP_NAME and other stuff aren't thread safe since if you call the child LLM app then continue working the baggage will get changed on you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed
attach_to_context
to check for existence + ensure that value is non null