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

Adding docs for instrument_openai #18

Merged
merged 5 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,31 @@
[![license](https://img.shields.io/github/license/pydantic/logfire.svg)](https://github.com/pydantic/logfire/blob/main/LICENSE)
[![versions](https://img.shields.io/pypi/pyversions/logfire.svg)](https://github.com/pydantic/logfire)

Logging like you always hoped it would be.

See the [documentation](https://docs.pydantic.dev/logfire/) for more information.

**Feel free to report issues and ask any questions about Logfire in this repository!**

This repo contains the Python SDK for `logfire` and documentation, the server application for recording and displaying data is closed source.
This repo contains the Python SDK for `logfire` and documentation; the server application for recording and displaying data is closed source.

## Using Logfire

This is a very brief overview of how to use Logfire, the [documentation](https://docs.pydantic.dev/logfire/) has much more detail.

## Setup
### Install

Install:
```bash
pip install logfire
```
[_(learn more)_](https://docs.pydantic.dev/logfire/guides/first_steps/#install)

Authenticate:
## Authenticate

```bash
logfire auth
```
[_(learn more)_](https://docs.pydantic.dev/logfire/guides/first_steps/#authentication)

## Usage
### Manual tracing

Here's a simple manual tracing (aka logging) example:

Expand All @@ -44,6 +46,8 @@ with logfire.span('Asking the user their {question}', question='age'):
```
[_(learn more)_](https://docs.pydantic.dev/logfire/guides/onboarding_checklist/03_add_manual_tracing/)

### Integration

Or you can also avoid manual instrumentation and instead integrate with [lots of popular packages](https://docs.pydantic.dev/logfire/integrations/), here's an example of integrating with FastAPI:

```py
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/logfire-screenshot-openai-stream.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/logfire-screenshot-openai.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 15 additions & 12 deletions docs/integrations/index.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
# Integrations

If a package you are using is not listed here, please let us know on our [Slack][slack]!

## Custom Integrations

Finally, we also have special integration with the Pydantic library and the OpenAI SDK:

| Package | Type |
|-------------------------|-----------------|
| [Pydantic](pydantic.md) | Data Validation |
| [OpenAI](openai.md) | AI |

## OpenTelemetry Integrations

Since **Pydantic Logfire** is [OpenTelemetry][opentelemetry] compatible, it can be used with any OpenTelemetry
instrumentation package. You can find the list of all OpenTelemetry instrumentation packages
[here](https://opentelemetry-python-contrib.readthedocs.io/en/latest/).

Below you can see the list of documented OpenTelemetry instrumentations.

If a package you are using is not listed here, please let us know on our [Slack][slack]!
Below you can see more details on how to use Logfire with some of the most popular Python packages.

| Package | Type |
|-------------------------------------|-------------------------|
Expand All @@ -30,7 +41,7 @@ If you are using Logfire with a web application, we also recommend reviewing
our [Web Frameworks](use_cases/web_frameworks.md)
documentation.

----
## Logging Integrations

We also have documentation for how to use Logfire with existing logging libraries:

Expand All @@ -40,14 +51,6 @@ We also have documentation for how to use Logfire with existing logging librarie
| [Loguru](loguru.md) | Logging |
| [Structlog](structlog.md) | Logging |

----

Finally, we also have special integration with the Pydantic library:

| Package | Type |
|-------------------------|-----------------|
| [Pydantic](pydantic.md) | Data Validation |

[slack]: https://join.slack.com/t/pydanticlogfire/shared_invite/zt-2b57ljub4-936siSpHANKxoY4dna7qng

[opentelemetry]: https://opentelemetry.io/
131 changes: 131 additions & 0 deletions docs/integrations/openai.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# OpenAI

## Introduction

Logfire supports instrumenting calls to OpenAI with one extra line of code.

```python hl_lines="6"
import openai
import logfire

client = openai.Client()

logfire.instrument_openai(client) # (1)!

response = client.chat.completions.create(
model='gpt-4',
messages=[
{'role': 'system', 'content': 'You are a helpful assistant.'},
{'role': 'user', 'content': 'Please write me a limerick about Python logging.'},
],
)
print(response.choices[0].text)
```

1. In general, `logfire.instrument_openai()` should be all you need.

_For more information, see the [`instrument_openai()` API reference][logfire.Logfire.instrument_openai]._

With that you get:

* a span around the call to OpenAI which records duration and captures any exceptions that might occur
* Human-readable display of the conversation with the agent
* details of the response, including the number of tokens used

<figure markdown="span">
![Logfire OpenAI](../images/logfire-screenshot-openai.png){ width="500" }
<figcaption>OpenAI span and conversation</figcaption>
</figure>

<figure markdown="span">
![Logfire OpenAI Arguments](../images/logfire-screenshot-openai-arguments.png){ width="500" }
<figcaption>Span arguments including response details</figcaption>
</figure>

## Methods covered

The following OpenAI methods are covered:

- [`client.chat.completions.create`](https://platform.openai.com/docs/guides/text-generation/chat-completions-api) — with and without `stream=True`
- [`client.completions.create`](https://platform.openai.com/docs/guides/text-generation/completions-api) — with and without `stream=True`
- [`client.embeddings.create`](https://platform.openai.com/docs/guides/embeddings/how-to-get-embeddings)
- [`client.images.generate`](https://platform.openai.com/docs/guides/images/generations)

All methods are covered with both `openai.Client` and `openai.AsyncClient`.

For example, here's instrumentation of an image generation call:

```python
import openai
import logfire

async def main():
client = openai.AsyncClient()
logfire.instrument_openai(client)

response = await client.images.generate(
prompt='Image of R2D2 running through a desert in the style of cyberpunk.',
model='dall-e-3',
)
url = response.data[0].url
import webbrowser
webbrowser.open(url)

if __name__ == '__main__':
import asyncio
asyncio.run(main())
```

Gives:

<figure markdown="span">
![Logfire OpenAI Image Generation](../images/logfire-screenshot-openai-image-gen.png){ width="500" }
<figcaption>OpenAI image generation span</figcaption>
</figure>

## Streaming Responses

When instrumenting streaming responses, Logfire creates two spans — one around the initial request and one
around the streamed response.

Here we also use Rich's [`Live`][rich.live.Live] and [`Markdown`][rich.markdown.Markdown] types to render the response in the terminal in real-time. :dancer:
Copy link
Contributor

Choose a reason for hiding this comment

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

🕺


```python
import openai
import logfire
from rich.console import Console
from rich.live import Live
from rich.markdown import Markdown

client = openai.AsyncClient()
logfire.instrument_openai(client)

async def main():
console = Console()
with logfire.span('Asking OpenAI to write some code'):
response = await client.chat.completions.create(
model='gpt-4',
messages=[
{'role': 'system', 'content': 'Reply in markdown one.'},
{'role': 'user', 'content': 'Write Python to show a tree of files 🤞.'},
],
stream=True
)
content = ''
with Live('', refresh_per_second=15, console=console) as live:
async for chunk in response:
if chunk.choices[0].delta.content is not None:
content += chunk.choices[0].delta.content
live.update(Markdown(content))

if __name__ == '__main__':
import asyncio
asyncio.run(main())
```

Shows up like this in Logfire:

<figure markdown="span">
![Logfire OpenAI Streaming](../images/logfire-screenshot-openai-stream.png){ width="500" }
<figcaption>OpenAI streaming response</figcaption>
</figure>
5 changes: 4 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ nav:
- Direct Database Connections: guides/advanced/06_direct_database_connections.md
- Integrations:
- Integrations: integrations/index.md
- Custom:
- Pydantic: integrations/pydantic.md
- OpenAI: integrations/openai.md
- OpenTelemetry:
- FastAPI: integrations/fastapi.md
- Django: integrations/django.md
Expand All @@ -116,7 +119,6 @@ nav:
- Logging: integrations/logging.md
- Structlog: integrations/structlog.md
- Loguru: integrations/loguru.md
- Pydantic: integrations/pydantic.md
- Use Cases:
- Web Frameworks: integrations/use_cases/web_frameworks.md
- Reference:
Expand Down Expand Up @@ -198,5 +200,6 @@ plugins:
- url: https://opentelemetry-python.readthedocs.io/en/latest/objects.inv
- url: https://requests.readthedocs.io/en/latest/objects.inv
- url: https://typing-extensions.readthedocs.io/en/latest/objects.inv
- url: https://rich.readthedocs.io/en/stable/objects.inv
hooks:
- docs/plugins/main.py