Vertex AI

Trace Gemini on Vertex AI in Python and TypeScript.

A google-genai / @google/genai client in Vertex mode is traced as provider="vertex_ai". generate_content, generate_content_stream, chat sessions, and embed_content are all captured, and the sampling params you pass (temperature, top_p, max_output_tokens) show up as model settings on the span.

Prerequisites

pip install -U "neatlogs[vertex-ai]" google-genai

Usage

import os
import neatlogs

neatlogs.init(api_key=os.environ["NEATLOGS_API_KEY"], workflow_name="vertex-demo")

from google import genai
from google.genai import types

# Express mode (API key). For ADC use:
#   genai.Client(vertexai=True, project=..., location="global")
client = neatlogs.wrap(genai.Client(vertexai=True, api_key=os.environ["GOOGLE_API_KEY"]))

resp = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="In one sentence, what is Vertex AI?",
    config=types.GenerateContentConfig(temperature=0.3, top_p=0.9, max_output_tokens=256),
)
print(resp.text)

neatlogs.flush()
neatlogs.shutdown()

wrap() opens a WORKFLOW root for you, so this renders with no extra wrapper.

Making several calls in one run? Group them into one trace with a WORKFLOW root.

Sessions & end-user

Say you're running a multi-turn Gemini chat on Vertex AI and you want every turn to fold into one session tied back to the user who's talking — that's a wrap of identify() around the turn. Because wrap() already opens the trace root, the wrapped Vertex call just inherits the session and end-user from the block around it:

# Same session_id every turn → one session; end_user_id attributes it to your user.
with neatlogs.identify(session_id=f"conv_{conversation_id}", end_user_id=user_id):
    resp = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=message,
    )

Not every run is a conversation. A standalone workflow — a one-off job, not a back-and-forth — is a single trace with no turns to group. You still attribute it to the customer it ran for, sourcing the id and any metadata from your own user or request object:

Warning

A standalone workflow must not carry a session_id. Omit it entirely — Neatlogs sets session_id = trace_id, so the run is its own single-turn session, fully attributed to the end-user. Reusing one session_id across unrelated runs wrongly folds them into a single multi-turn conversation.

def summarize(document, user):
    # Standalone workflow — attribute to the end-user; do NOT pass session_id.
    with neatlogs.identify(
        end_user_id=str(user.id),
        end_user_metadata={"plan": user.plan},
    ):
        resp = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=f"Summarize:\n{document}",
        )
        return resp.text

Sessions and End-User Identity walk through the full model.

On this page

Ask Neatlogs AI

Answers from the docs

How can I help?

Ask anything about instrumenting, tracing, or the Neatlogs dashboard.