From ebcd146181ebb88078a5ac7b39bbea36fae5d2a7 Mon Sep 17 00:00:00 2001 From: kenvora Date: Wed, 12 Aug 2026 19:09:17 -0700 Subject: [PATCH 1/3] feat: add scripts to capture sandbox/engine/gateway (LCU/LSU) usage --- .../scripts/run_all_full_exports_pg.sh | 100 ++++++++++++++++++ ..._usage_engine_intelligence_full_export.sql | 7 ++ ..._usage_engine_issues_agent_full_export.sql | 10 ++ .../pg_usage_langchain_usage_full_export.sql | 12 +++ .../postgres/pg_usage_sandbox_full_export.sql | 8 ++ 5 files changed, 137 insertions(+) create mode 100755 charts/langsmith/scripts/run_all_full_exports_pg.sh create mode 100644 charts/langsmith/scripts/support_queries/postgres/pg_usage_engine_intelligence_full_export.sql create mode 100644 charts/langsmith/scripts/support_queries/postgres/pg_usage_engine_issues_agent_full_export.sql create mode 100644 charts/langsmith/scripts/support_queries/postgres/pg_usage_langchain_usage_full_export.sql create mode 100644 charts/langsmith/scripts/support_queries/postgres/pg_usage_sandbox_full_export.sql diff --git a/charts/langsmith/scripts/run_all_full_exports_pg.sh b/charts/langsmith/scripts/run_all_full_exports_pg.sh new file mode 100755 index 00000000..6eb95590 --- /dev/null +++ b/charts/langsmith/scripts/run_all_full_exports_pg.sh @@ -0,0 +1,100 @@ +#!/bin/sh + +# Runs every pg_usage_*_full_export.sql support query against a self-hosted +# LangSmith Postgres in one shot and writes one CSV per dataset into an output +# directory, then (if tar is available) bundles them into a single .tar.gz for +# easy transfer. This wraps run_support_query_pg.sh so DB URL parsing, psql +# flags, and PGPASSWORD handling stay in one place. +# +# Only the read-only *_full_export.sql scripts are run — never the +# *_backfill_export.sql / *_backfill_update.sql scripts (those mutate rows) nor +# the non-usage pg_get_* support queries. + +print_usage_and_exit() { + echo "Error: $1" + echo "Usage: $0 [--output-dir ] [--debug]" + echo "Example: $0 postgres://username:password@host:port/database --output-dir ./langsmith-usage-export" + echo "Note: must be postgres://user:password@host:port/database (explicit port, no query string), same as run_support_query_pg.sh." + exit 1 +} + +postgres_url="" +output_dir="langsmith-usage-export" +debug="" + +while [ $# -gt 0 ]; do + case "$1" in + --output-dir) + [ -n "$2" ] || print_usage_and_exit "Missing value for --output-dir" + output_dir="$2" + shift 2 + ;; + --debug) + debug="--debug" + shift + ;; + *) + if [ -z "$postgres_url" ]; then + postgres_url="$1" + shift + else + print_usage_and_exit "Unknown argument: $1" + fi + ;; + esac +done + +if [ -z "$postgres_url" ]; then + print_usage_and_exit "PostgreSQL URL is required." +fi + +script_dir=$(dirname -- "$0") +script_dir=$(cd -- "$script_dir" && pwd) +runner="$script_dir/run_support_query_pg.sh" +query_dir="$script_dir/support_queries/postgres" + +[ -f "$runner" ] || print_usage_and_exit "runner not found: $runner" +[ -d "$query_dir" ] || print_usage_and_exit "query dir not found: $query_dir" + +mkdir -p "$output_dir" || print_usage_and_exit "could not create output dir: $output_dir" + +# run_support_query_pg.sh uses bash arrays / [[ =~ ]], so invoke it with bash +# explicitly rather than relying on its shebang. +runner_shell="sh" +if command -v bash >/dev/null 2>&1; then + runner_shell="bash" +fi + +count=0 +failed=0 +for sql in "$query_dir"/pg_usage_*_full_export.sql; do + [ -e "$sql" ] || continue # no-match guard when the glob matches nothing + name=$(basename "$sql" .sql) + label=${name#pg_usage_} + label=${label%_full_export} + out="$output_dir/${label}.csv" + echo "==> exporting ${label} -> ${out}" + if "$runner_shell" "$runner" "$postgres_url" $debug --input "$sql" --output "$out"; then + count=$((count + 1)) + else + echo "!! export failed for ${label} (continuing)" + failed=$((failed + 1)) + fi +done + +if [ "$count" -eq 0 ] && [ "$failed" -eq 0 ]; then + print_usage_and_exit "no pg_usage_*_full_export.sql scripts found in $query_dir" +fi + +# Bundle the CSVs into one archive for easy transfer, when tar is available. +if command -v tar >/dev/null 2>&1; then + archive="${output_dir%/}.tar.gz" + parent=$(dirname -- "$output_dir") + base=$(basename -- "$output_dir") + if tar -czf "$archive" -C "$parent" "$base"; then + echo "Bundled ${count} CSV(s) into ${archive}" + fi +fi + +echo "Done. ${count} export(s) written to ${output_dir}/ (${failed} failed)." +[ "$failed" -eq 0 ] || exit 1 diff --git a/charts/langsmith/scripts/support_queries/postgres/pg_usage_engine_intelligence_full_export.sql b/charts/langsmith/scripts/support_queries/postgres/pg_usage_engine_intelligence_full_export.sql new file mode 100644 index 00000000..416903b1 --- /dev/null +++ b/charts/langsmith/scripts/support_queries/postgres/pg_usage_engine_intelligence_full_export.sql @@ -0,0 +1,7 @@ +-- This query exports all Smith Intelligence (self-hosted Engine) token usage. It +-- already carries customer_id, organization_id and tenant_id, so no join needed. + +SELECT + sit.* +FROM smith_intelligence_token_usage sit +ORDER BY sit.hour_start DESC; diff --git a/charts/langsmith/scripts/support_queries/postgres/pg_usage_engine_issues_agent_full_export.sql b/charts/langsmith/scripts/support_queries/postgres/pg_usage_engine_issues_agent_full_export.sql new file mode 100644 index 00000000..05311aff --- /dev/null +++ b/charts/langsmith/scripts/support_queries/postgres/pg_usage_engine_issues_agent_full_export.sql @@ -0,0 +1,10 @@ +-- This query exports all legacy issues-agent (Engine) token usage. It is +-- tenant-scoped only, so LEFT JOIN tenants to recover organization_id (LEFT so a +-- row with no matching tenant still exports). + +SELECT + iat.*, + t.organization_id +FROM issues_agent_token_usage iat +LEFT JOIN tenants t ON iat.tenant_id = t.id +ORDER BY iat.hour_start DESC; diff --git a/charts/langsmith/scripts/support_queries/postgres/pg_usage_langchain_usage_full_export.sql b/charts/langsmith/scripts/support_queries/postgres/pg_usage_langchain_usage_full_export.sql new file mode 100644 index 00000000..37fc5cea --- /dev/null +++ b/charts/langsmith/scripts/support_queries/postgres/pg_usage_langchain_usage_full_export.sql @@ -0,0 +1,12 @@ +-- This query exports all langchain_usage rows — the shared LCU/LSU store for the +-- newer products (sandbox-priced, LSD/engine, gateway_hosted_models, fleet), +-- distinguished by the product / usage_type / metric_type columns. +-- langchain_usage carries only tenant_id, so LEFT JOIN tenants to recover +-- organization_id (LEFT so a row with no matching tenant still exports). + +SELECT + lu.*, + t.organization_id +FROM langchain_usage lu +LEFT JOIN tenants t ON lu.tenant_id = t.id +ORDER BY lu.bucket_start DESC; diff --git a/charts/langsmith/scripts/support_queries/postgres/pg_usage_sandbox_full_export.sql b/charts/langsmith/scripts/support_queries/postgres/pg_usage_sandbox_full_export.sql new file mode 100644 index 00000000..957ca088 --- /dev/null +++ b/charts/langsmith/scripts/support_queries/postgres/pg_usage_sandbox_full_export.sql @@ -0,0 +1,8 @@ +-- This query exports all sandbox uptime usage — the raw sandbox outbox. It +-- already carries organization_id and the self-hosted attribution columns, so no +-- join is needed. + +SELECT + su.* +FROM sandbox_uptime_usage su +ORDER BY su.period_start DESC; From 16e6d272c67e6ce4c2aa284e6640d9028f7c7220 Mon Sep 17 00:00:00 2001 From: kenvora Date: Wed, 12 Aug 2026 19:31:09 -0700 Subject: [PATCH 2/3] updates --- .../scripts/run_all_full_exports_pg.sh | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/charts/langsmith/scripts/run_all_full_exports_pg.sh b/charts/langsmith/scripts/run_all_full_exports_pg.sh index 6eb95590..ec0bde88 100755 --- a/charts/langsmith/scripts/run_all_full_exports_pg.sh +++ b/charts/langsmith/scripts/run_all_full_exports_pg.sh @@ -10,11 +10,48 @@ # *_backfill_export.sql / *_backfill_update.sql scripts (those mutate rows) nor # the non-usage pg_get_* support queries. +usage() { + cat <<'EOF' +Run every read-only pg_usage_*_full_export.sql support query in one shot, write +one CSV per usage dataset, then (if tar is available) bundle them into a single +.tar.gz for transfer. Wraps run_support_query_pg.sh, which handles the DB +connection and PGPASSWORD. Only *_full_export.sql scripts are run — never the +mutating *_backfill_* scripts. + +Usage: + run_all_full_exports_pg.sh [--output-dir ] [--debug] + run_all_full_exports_pg.sh --help + +Arguments: + postgres://user:password@host:port/database + Explicit port, no query string (URL-encode any special + characters in the password). For the bundled Postgres this + is postgres://postgres:postgres@localhost:5432/postgres — + port-forward first: + kubectl port-forward svc/langsmith-postgres 5432:5432 + +Options: + --output-dir Directory for the per-dataset CSVs + (default: ./langsmith-usage-export). Bundled as .tar.gz. + --debug Verbose psql output. + -h, --help Show this help and exit. + +Output — one CSV per dataset: + traces, nodes, agent_builder, snapshots, + langchain_usage, sandbox, engine_intelligence, engine_issues_agent + +If a dataset's table is absent on an older deployment, that export is skipped +with a warning and the rest continue; the script exits non-zero if any failed. + +Example: + sh run_all_full_exports_pg.sh "postgres://postgres:postgres@localhost:5432/postgres" +EOF +} + print_usage_and_exit() { - echo "Error: $1" - echo "Usage: $0 [--output-dir ] [--debug]" - echo "Example: $0 postgres://username:password@host:port/database --output-dir ./langsmith-usage-export" - echo "Note: must be postgres://user:password@host:port/database (explicit port, no query string), same as run_support_query_pg.sh." + echo "Error: $1" >&2 + echo >&2 + usage >&2 exit 1 } @@ -24,6 +61,10 @@ debug="" while [ $# -gt 0 ]; do case "$1" in + -h|--help) + usage + exit 0 + ;; --output-dir) [ -n "$2" ] || print_usage_and_exit "Missing value for --output-dir" output_dir="$2" From f9e0cbf22d0a01285c9acf3dc728e90fb7a86b48 Mon Sep 17 00:00:00 2001 From: kenvora Date: Wed, 12 Aug 2026 19:32:15 -0700 Subject: [PATCH 3/3] updates --- charts/langsmith/docs/RUN-SUPPORT-QUERY-PG.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/charts/langsmith/docs/RUN-SUPPORT-QUERY-PG.md b/charts/langsmith/docs/RUN-SUPPORT-QUERY-PG.md index 20c2e535..635f9e96 100644 --- a/charts/langsmith/docs/RUN-SUPPORT-QUERY-PG.md +++ b/charts/langsmith/docs/RUN-SUPPORT-QUERY-PG.md @@ -48,3 +48,27 @@ sh run_support_query_pg.sh "postgres://postgres:postgres@localhost:5432/postgres ``` which will output the count of daily traces by workspace ID and organization ID. To extract this to a file add the flag `--output path/to/file.csv` + +### Exporting all usage data at once + +To export every usage dataset in one command — instead of running each +`pg_usage_*_full_export.sql` individually — use `run_all_full_exports_pg.sh`. It +runs all read-only full-export queries, writes one CSV per dataset, and (if +`tar` is available) bundles them into a single `.tar.gz` for transfer. It only +runs the read-only `*_full_export.sql` scripts, never the `*_backfill_*` ones. + +```bash +sh run_all_full_exports_pg.sh +``` + +For example, if you are using the bundled version with port-forwarding: + +```bash +sh run_all_full_exports_pg.sh "postgres://postgres:postgres@localhost:5432/postgres" +``` + +This writes one CSV per dataset into `./langsmith-usage-export/` (`traces`, +`nodes`, `agent_builder`, `snapshots`, `langchain_usage`, `sandbox`, +`engine_intelligence`, `engine_issues_agent`) and bundles +`./langsmith-usage-export.tar.gz`. Pass `--output-dir ` to change the +location, `--debug` for verbose psql output, or `--help` for full usage.