> ## Documentation Index
> Fetch the complete documentation index at: https://docs.honeyhive.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from Logger to v1

> Replace honeyhive-logger start, log, and update calls with the HoneyHive Python SDK v1 tracer.

The `honeyhive-logger` package is a lightweight API wrapper with `start()`, `log()`, and `update()` functions. The v1 `honeyhive` package adds OpenTelemetry tracing, automatic context propagation, decorators, instrumentors, and evaluation support.

Use this guide when moving Python code from `honeyhive-logger` to `honeyhive>=1.0.0`.

<Note>
  The logger package is useful when you need a dependency-free client. Migrate to the v1 SDK when you want automatic spans, nested trace trees, framework integrations, or `evaluate()`.
</Note>

<Accordion title="Use a coding agent to migrate">
  ```text theme={null}
  Use this HoneyHive migration guide: https://docs.honeyhive.ai/v2/sdk-reference/python/migration/logger-to-v1.md

  Explore my codebase to find where HoneyHive logging is used. Ask me any questions needed to understand the project context, runtime, and migration constraints. Then present a concise migration plan for my confirmation. After I confirm the plan, implement the migration changes.
  ```
</Accordion>

## API mapping

| Logger API                            | v1 SDK replacement                                                                        | Notes                                                                                                       |
| ------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| *(no logger equivalent)*              | `HoneyHiveTracer.init(...)`                                                               | New in v1: call once at app startup before any logger replacement.                                          |
| `start(...)`                          | `tracer.create_session(...)` / `tracer.acreate_session(...)` / `tracer.with_session(...)` | Choose `with_session()` for scoped blocks, `acreate_session()` for async frameworks (FastAPI, async Flask). |
| `log(...)` (creates a new event)      | `@trace` or `enrich_span_context(...)`                                                    | Both create a new span/event. Prefer decorators for function-level tracing.                                 |
| `log(...)` then enrich the same event | `tracer.enrich_span(...)` inside the active span                                          | `enrich_span()` attaches fields to the currently active span. It does **not** create a new span on its own. |
| `update(event_id=...)`                | `tracer.enrich_span(event_id=...)`                                                        | Updates a specific existing event by ID via the events API.                                                 |
| `update(event_id=session_id, ...)`    | `tracer.enrich_session(session_id=...)`                                                   | Updates a session.                                                                                          |
| `duration_ms`                         | Captured by spans automatically                                                           | Use `metrics` only if you need custom duration fields.                                                      |

***

## 1. Replace the package

```bash theme={null}
pip uninstall honeyhive-logger -y
pip install "honeyhive>=1.0.0"
```

Set credentials:

```bash theme={null}
export HH_API_KEY="your-honeyhive-api-key"
export HH_SOURCE="production"
```

<Note>
  **You no longer need to set `HH_PROJECT` or pass `project=` to `HoneyHiveTracer.init()`.** HoneyHive API keys are project-scoped — the API key alone determines which project traces are routed to. Drop `HH_PROJECT` and `project=` anywhere they are set in logger code; neither has any effect on the API or SDK behavior. Passing `project=` explicitly to `HoneyHiveTracer.init(...)` emits a `DeprecationWarning` because the kwarg will be removed in v2.0. The examples below use `HoneyHiveTracer.init()` with no kwargs.
</Note>

***

## 2. Migrate session creation

Logger code usually starts a session and passes `session_id` to every event. In v1, initialize a tracer once and use session helpers to scope work.

<CodeGroup>
  ```python Logger theme={null}
  import os
  from honeyhive_logger import start

  session_id = start(
      api_key=os.environ["HH_API_KEY"],
      project="support-bot",
      session_name="support-chat",
      source="production",
      inputs={"message": "How do I reset my password?"},
      metadata={"tenant_id": "acme"},
      user_properties={"user_id": "user-123"},
  )
  ```

  ```python v1 SDK theme={null}
  from honeyhive import HoneyHiveTracer

  # Reads HH_API_KEY and HH_SOURCE from the environment.
  tracer = HoneyHiveTracer.init()

  session_id = tracer.create_session(
      session_name="support-chat",
      inputs={"message": "How do I reset my password?"},
      metadata={"tenant_id": "acme"},
      user_properties={"user_id": "user-123"},
  )
  ```
</CodeGroup>

For async frameworks (FastAPI, async Flask), use `await tracer.acreate_session(...)` — same arguments as `create_session()`.

<Tip>
  Unlike the logger, the v1 SDK can serve concurrent requests safely from a single shared `tracer` because `create_session()` / `acreate_session()` / `with_session()` store the session ID in OpenTelemetry baggage (`ContextVar`-based) rather than on the tracer instance. See [Tracer Initialization](/v2/tracing/tracer-initialization) for FastAPI, Flask, and Lambda patterns.
</Tip>

For single-operation scripts, `with_session()` keeps session setup close to the work:

```python theme={null}
with tracer.with_session(
    session_name="support-chat",
    inputs={"message": message},
    user_properties={"user_id": user_id},
):
    response = answer(message)
    tracer.enrich_session(outputs={"response": response})
```

***

## 3. Replace `log()` with `@trace`

Use `@trace` when the event maps to a Python function.

<CodeGroup>
  ```python Logger theme={null}
  from honeyhive_logger import log

  def answer(message: str, session_id: str) -> str:
      response = call_model(message)
      log(
          session_id=session_id,
          event_name="model_inference",
          event_type="model",
          config={"model": "gpt-4o-mini"},
          inputs={"prompt": message},
          outputs={"response": response},
          metadata={"route": "password-reset"},
      )
      return response
  ```

  ```python v1 SDK theme={null}
  from honeyhive import trace

  @trace(
      event_name="model_inference",
      event_type="model",
      tracer=tracer,
  )
  def answer(message: str) -> str:
      tracer.enrich_span(
          config={"model": "gpt-4o-mini"},
          metadata={"route": "password-reset"},
      )
      response = call_model(message)
      tracer.enrich_span(outputs={"response": response})
      return response
  ```
</CodeGroup>

The decorator captures function inputs and outputs automatically. Use `tracer.enrich_span(...)` inside the function for extra metadata, metrics, feedback, config, or a custom output shape.

***

## 4. Replace `log()` with manual spans when decorators do not fit

Use `enrich_span_context()` for loops, conditional blocks, or code that is not cleanly wrapped by a function.

<CodeGroup>
  ```python Logger theme={null}
  event_id = log(
      session_id=session_id,
      event_name="retrieve_documents",
      event_type="tool",
      inputs={"query": query},
      outputs={"documents": docs},
  )
  ```

  ```python v1 SDK theme={null}
  from honeyhive.tracer.processing.context import enrich_span_context

  with enrich_span_context(
      event_name="retrieve_documents",
      inputs={"query": query},
      attributes={"honeyhive_event_type": "tool"},
      tracer_instance=tracer,
  ):
      docs = retrieve_documents(query)
      tracer.enrich_span(outputs={"documents": docs})
  ```
</CodeGroup>

<Note>
  In `honeyhive>=1.0.0`, `enrich_span_context` is not re-exported at `honeyhive` or `honeyhive.tracer`. Import it from `honeyhive.tracer.processing.context`. Always pass `tracer_instance=tracer` — otherwise the helper falls back to an unconfigured OpenTelemetry tracer and spans will not reach HoneyHive. `enrich_span_context` does not expose an `event_type` parameter; set it via the raw `attributes={"honeyhive_event_type": "tool"}` attribute when migrating a `log(event_type=...)` call.
</Note>

Use `tracer.start_span()` only when you need raw OpenTelemetry control:

```python theme={null}
with tracer.start_span("retrieve_documents") as span:
    span.set_attribute("query", query)
    docs = retrieve_documents(query)
    span.set_attribute("document_count", len(docs))
```

***

## 5. Replace `update()` for events

When you need to update a known event ID, pass it to `tracer.enrich_span()`.

<Note>
  Use `event_id` when you want to update an existing event in HoneyHive. If you are updating the current active span, omit `event_id`.
</Note>

<Tip>
  **Getting an `event_id` back.** The `@trace` decorator and `enrich_span_context()` do not return event IDs — they manage span IDs through OpenTelemetry context. If you need the same "create event, hold on to its ID, update it later" pattern as the logger, use the lower-level `tracer.create_event(...)` method, which posts the event directly via the events API and returns its ID.

  ```python theme={null}
  event_id = tracer.create_event(
      event_name="model_inference",
      event_type="model",
      inputs={"prompt": message},
      outputs={"response": response},
  )
  # ...later, anywhere in the codebase
  tracer.enrich_span(event_id=event_id, feedback={"rating": 5})
  ```

  There is also an `update_event_id` parameter on `tracer.enrich_span(...)` that lets you tag the current span with a client-supplied UUID and later look that event up with `enrich_span(event_id=...)`, but the round-trip depends on backend behavior we have not validated end-to-end — prefer the `create_event` path above unless you have already confirmed the UUID flow against your HoneyHive deployment.
</Tip>

<CodeGroup>
  ```python Logger theme={null}
  from honeyhive_logger import update

  update(
      event_id=event_id,
      feedback={"rating": 5},
      metrics={"quality_score": 0.94},
      outputs={"response": response},
  )
  ```

  ```python v1 SDK theme={null}
  tracer.enrich_span(
      event_id=event_id,
      feedback={"rating": 5},
      metrics={"quality_score": 0.94},
      outputs={"response": response},
  )
  ```
</CodeGroup>

If the event is the current active span, omit `event_id`:

```python theme={null}
tracer.enrich_span(
    feedback={"rating": 5},
    metrics={"quality_score": 0.94},
)
```

***

## 6. Replace `update()` for sessions

Logger uses `update(event_id=session_id, ...)` for session updates. In v1, use session enrichment.

<CodeGroup>
  ```python Logger theme={null}
  update(
      event_id=session_id,
      outputs={"answer": answer_text},
      feedback={"thumbs_up": True},
      user_properties={"plan": "enterprise"},
  )
  ```

  ```python v1 SDK theme={null}
  tracer.enrich_session(
      session_id=session_id,
      outputs={"answer": answer_text},
      feedback={"thumbs_up": True},
      user_properties={"plan": "enterprise"},
  )
  ```
</CodeGroup>

If you created the session with `create_session()` in the active request, you can omit `session_id`:

```python theme={null}
tracer.enrich_session(outputs={"answer": answer_text})
```

***

## 7. Add automatic provider instrumentation

After migrating logger calls, you can add automatic model or framework spans.

```bash theme={null}
pip install "honeyhive[openinference-openai]"
```

```python theme={null}
from honeyhive import HoneyHiveTracer
from openinference.instrumentation.openai import OpenAIInstrumentor

# Reads HH_API_KEY from the environment.
tracer = HoneyHiveTracer.init()
OpenAIInstrumentor().instrument(tracer_provider=tracer.provider)
```

Initialize the tracer **before** any instrumentor, and call `instrument()` before constructing your provider client (for example, `openai.OpenAI()`). See [Integrations](/v2/integrations/openai) for provider-specific setup.

***

## Complete before and after

<CodeGroup>
  ```python Logger theme={null}
  from honeyhive_logger import start, log, update

  def handle_chat(message: str, user_id: str) -> str:
      session_id = start(
          session_name="support-chat",
          inputs={"message": message},
          user_properties={"user_id": user_id},
      )

      response = call_model(message)
      event_id = log(
          session_id=session_id,
          event_name="model_inference",
          event_type="model",
          inputs={"prompt": message},
          outputs={"response": response},
      )

      update(event_id=event_id, metrics={"quality_score": score(response)})
      update(event_id=session_id, outputs={"response": response})
      return response
  ```

  ```python v1 SDK theme={null}
  from honeyhive import HoneyHiveTracer, trace

  # Reads HH_API_KEY and HH_SOURCE from the environment.
  tracer = HoneyHiveTracer.init()

  @trace(event_name="model_inference", event_type="model", tracer=tracer)
  def call_traced_model(message: str) -> str:
      response = call_model(message)
      tracer.enrich_span(metrics={"quality_score": score(response)})
      return response

  def handle_chat(message: str, user_id: str) -> str:
      with tracer.with_session(
          session_name="support-chat",
          inputs={"message": message},
          user_properties={"user_id": user_id},
      ):
          response = call_traced_model(message)
          tracer.enrich_session(outputs={"response": response})
          return response
  ```
</CodeGroup>

<Warning>
  **Flush before process exit in short-lived scripts.** Unlike `honeyhive-logger`, which sends each call synchronously, the v1 SDK batches spans on a background thread by default. For scripts, notebooks, Lambda handlers, and one-off jobs, call `tracer.flush()` (or initialize with `disable_batch=True`) before the process exits, otherwise the last batch of spans may be dropped. See [Span Export Modes](/v2/tracing/tracer-initialization#span-export-modes).
</Warning>

***

## Migration checklist

* [ ] Replace `honeyhive-logger` with `honeyhive>=1.0.0`
* [ ] Export `HH_API_KEY` in the environment (API keys are project-scoped; remove any `HH_PROJECT` or `project=` left over from logger code)
* [ ] Initialize one `HoneyHiveTracer` at startup
* [ ] Replace `start()` with `create_session()`, `acreate_session()`, or `with_session()`
* [ ] Replace function-level `log()` calls with `@trace`
* [ ] Replace block-level `log()` calls with `enrich_span_context()`
* [ ] Replace event `update()` calls with `tracer.enrich_span(event_id=...)`
* [ ] Replace session `update()` calls with `tracer.enrich_session(...)`
* [ ] Call `tracer.flush()` (or set `disable_batch=True`) for scripts, notebooks, and serverless handlers
* [ ] Add provider instrumentors where automatic tracing is useful
* [ ] Confirm traces show nested spans and session outputs in HoneyHive

## Related

<CardGroup cols={2}>
  <Card title="Custom Spans" icon="code" href="/v2/tracing/custom-spans">
    Learn decorator and manual span patterns.
  </Card>

  <Card title="Tracer Initialization" icon="route" href="/v2/tracing/tracer-initialization">
    Place tracer initialization correctly for your runtime.
  </Card>

  <Card title="Enriching Traces" icon="sparkles" href="/v2/tracing/enrich-traces">
    Add metadata, metrics, feedback, and outputs.
  </Card>

  <Card title="OpenAI Integration" icon="plug" href="/v2/integrations/openai">
    Add automatic model call tracing.
  </Card>
</CardGroup>
