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

Add env vars #192

Merged
merged 2 commits into from
Sep 1, 2023
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
48 changes: 48 additions & 0 deletions js/src/utils/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ let runtimeEnvironment: RuntimeEnvironment | undefined;
export async function getRuntimeEnvironment(): Promise<RuntimeEnvironment> {
if (runtimeEnvironment === undefined) {
const env = getEnv();
const releaseEnv = getShas();

runtimeEnvironment = {
library: "langsmith",
runtime: env,
...releaseEnv,
};
}
return runtimeEnvironment;
Expand All @@ -93,3 +95,49 @@ export function setEnvironmentVariable(name: string, value: string): void {
process.env[name] = value;
}
}

interface ICommitSHAs {
[key: string]: string;
}
let cachedCommitSHAs: ICommitSHAs | undefined;
/**
* Get the Git commit SHA from common environment variables
* used by different CI/CD platforms.
* @returns {string | undefined} The Git commit SHA or undefined if not found.
*/
export function getShas(): ICommitSHAs {
if (cachedCommitSHAs !== undefined) {
return cachedCommitSHAs;
}
const common_release_envs = [
"VERCEL_GIT_COMMIT_SHA",
"NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA",
"COMMIT_REF",
"RENDER_GIT_COMMIT",
"CI_COMMIT_SHA",
"CIRCLE_SHA1",
"CF_PAGES_COMMIT_SHA",
"REACT_APP_GIT_SHA",
"SOURCE_VERSION",
"GITHUB_SHA",
"TRAVIS_COMMIT",
"GIT_COMMIT",
"BUILD_VCS_NUMBER",
"bamboo_planRepository_revision",
"Build.SourceVersion",
"BITBUCKET_COMMIT",
"DRONE_COMMIT_SHA",
"SEMAPHORE_GIT_SHA",
"BUILDKITE_COMMIT",
] as const;

const shas: ICommitSHAs = {};
for (const env of common_release_envs) {
const envVar = getEnvironmentVariable(env);
if (envVar !== undefined) {
shas[env] = envVar;
}
}
cachedCommitSHAs = shas;
return shas;
}
13 changes: 5 additions & 8 deletions python/langsmith/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@

import requests

from langsmith.utils import (
get_docker_compose_command,
get_docker_environment,
get_runtime_environment,
)
from langsmith import env as ls_env
from langsmith import utils as ls_utils

logging.basicConfig(level=logging.INFO, format="%(message)s")
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -150,7 +147,7 @@ def __init__(self) -> None:

@property
def docker_compose_command(self) -> List[str]:
return get_docker_compose_command()
return ls_utils.get_docker_compose_command()

def _open_browser(self, url: str) -> None:
try:
Expand Down Expand Up @@ -360,8 +357,8 @@ def status(self) -> None:

def env() -> None:
"""Print the runtime environment information."""
env = get_runtime_environment()
env.update(get_docker_environment())
env = ls_env.get_runtime_environment()
env.update(ls_env.get_docker_environment())

# calculate the max length of keys
max_key_length = max(len(key) for key in env.keys())
Expand Down
3 changes: 2 additions & 1 deletion python/langsmith/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from requests import adapters as requests_adapters
from urllib3.util import Retry

from langsmith import env as ls_env
from langsmith import schemas as ls_schemas
from langsmith import utils as ls_utils
from langsmith.evaluation.evaluator import RunEvaluator
Expand Down Expand Up @@ -600,7 +601,7 @@ def create_run(
}
run_extra = cast(dict, run_create.setdefault("extra", {}))
runtime = run_extra.setdefault("runtime", {})
runtime_env = ls_utils.get_runtime_environment()
runtime_env = ls_env.get_runtime_and_metrics()
run_extra["runtime"] = {**runtime_env, **runtime}
headers = {**self._headers, "Accept": "application/json"}
self.request_with_retries(
Expand Down
164 changes: 164 additions & 0 deletions python/langsmith/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""Environment information."""
import functools
import os
import platform
import subprocess
from typing import Dict, List, Optional, Union

from langsmith.utils import get_docker_compose_command

try:
# psutil is an optional dependency
import psutil

_PSUTIL_AVAILABLE = True
except ImportError:
_PSUTIL_AVAILABLE = False


def get_runtime_and_metrics() -> dict:
"""Get the runtime information as well as metrics."""
return {**get_runtime_environment(), **get_system_metrics()}


def get_system_metrics() -> Dict[str, Union[float, dict]]:
"""Get CPU and other performance metrics."""
if not _PSUTIL_AVAILABLE:
return {}
process = psutil.Process(os.getpid())
metrics: Dict[str, Union[float, dict]] = {}

with process.oneshot():
mem_info = process.memory_info()
metrics["thread_count"] = float(process.num_threads())
metrics["mem"] = {
"rss": float(mem_info.rss),
}
ctx_switches = process.num_ctx_switches()
cpu_times = process.cpu_times()
metrics["cpu"] = {
"time": {
"sys": cpu_times.system,
"user": cpu_times.user,
},
"ctx_switches": {
"voluntary": float(ctx_switches.voluntary),
"involuntary": float(ctx_switches.involuntary),
},
"percent": process.cpu_percent(),
}
return metrics


@functools.lru_cache(maxsize=1)
def get_runtime_environment() -> dict:
"""Get information about the environment."""
# Lazy import to avoid circular imports
from langsmith import __version__

shas = get_release_shas()
return {
"sdk_version": __version__,
"library": "langsmith",
"platform": platform.platform(),
"runtime": "python",
"py_implementation": platform.python_implementation(),
"runtime_version": platform.python_version(),
"langchain_version": get_langchain_environment(),
**shas,
}


@functools.lru_cache(maxsize=1)
def get_langchain_environment() -> Optional[str]:
try:
import langchain # type: ignore

return langchain.__version__
except: # noqa
return None


@functools.lru_cache(maxsize=1)
def get_docker_version() -> Optional[str]:
import subprocess

try:
docker_version = (
subprocess.check_output(["docker", "--version"]).decode("utf-8").strip()
)
except FileNotFoundError:
docker_version = "unknown"
except: # noqa
return None
return docker_version


@functools.lru_cache(maxsize=1)
def get_docker_compose_version() -> Optional[str]:
try:
docker_compose_version = (
subprocess.check_output(["docker-compose", "--version"])
.decode("utf-8")
.strip()
)
except FileNotFoundError:
docker_compose_version = "unknown"
except: # noqa
return None
return docker_compose_version


@functools.lru_cache(maxsize=1)
def _get_compose_command() -> Optional[List[str]]:
try:
compose_command = get_docker_compose_command()
except ValueError as e:
compose_command = [f"NOT INSTALLED: {e}"]
except: # noqa
return None
return compose_command


@functools.lru_cache(maxsize=1)
def get_docker_environment() -> dict:
"""Get information about the environment."""
compose_command = _get_compose_command()
return {
"docker_version": get_docker_version(),
"docker_compose_command": " ".join(compose_command)
if compose_command is not None
else None,
"docker_compose_version": get_docker_compose_version(),
}


@functools.lru_cache(maxsize=1)
def get_release_shas() -> Dict[str, str]:
common_release_envs = [
"VERCEL_GIT_COMMIT_SHA",
"NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA",
"COMMIT_REF",
"RENDER_GIT_COMMIT",
"CI_COMMIT_SHA",
"CIRCLE_SHA1",
"CF_PAGES_COMMIT_SHA",
"REACT_APP_GIT_SHA",
"SOURCE_VERSION",
"GITHUB_SHA",
"TRAVIS_COMMIT",
"GIT_COMMIT",
"BUILD_VCS_NUMBER",
"bamboo_planRepository_revision",
"Build.SourceVersion",
"BITBUCKET_COMMIT",
"DRONE_COMMIT_SHA",
"SEMAPHORE_GIT_SHA",
"BUILDKITE_COMMIT",
]
shas = {}
for env in common_release_envs:
env_var = os.environ.get(env)
if env_var is not None:
shas[env] = env_var
return shas
8 changes: 4 additions & 4 deletions python/langsmith/run_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ def _setup_run(
docstring = func.__doc__
extra_inner = _collect_extra(extra_outer, langsmith_extra)
metadata_ = {**(metadata or {}), **(langsmith_extra.get("metadata") or {})}
if metadata_:
extra_inner["metadata"] = metadata_
metadata_["ls_method"] = "traceable"
extra_inner["metadata"] = metadata_
inputs = _get_inputs(signature, *args, **kwargs)
tags_ = (tags or []) + (langsmith_extra.get("tags") or [])
id_ = langsmith_extra.get("run_id", uuid.uuid4())
Expand Down Expand Up @@ -281,8 +281,8 @@ def trace(
) -> Generator[run_trees.RunTree, None, None]:
"""Context manager for creating a run tree."""
extra_outer = extra or {}
if metadata:
extra_outer["metadata"] = metadata
metadata = metadata or {}
extra_outer["metadata"] = {**metadata, "ls_method": "trace"}
parent_run_ = _PARENT_RUN_TREE.get() if run_tree is None else run_tree
outer_project = _PROJECT_NAME.get() or os.environ.get(
"LANGCHAIN_PROJECT", os.environ.get("LANGCHAIN_PROJECT", "default")
Expand Down
5 changes: 1 addition & 4 deletions python/langsmith/run_trees.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

from langsmith.client import ID_TYPE, Client
from langsmith.schemas import RunBase
from langsmith.utils import get_runtime_environment

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -91,9 +90,7 @@ def infer_defaults(cls, values: dict) -> dict:
values["child_execution_order"] = values["execution_order"]
if values.get("parent_run") is not None:
values["parent_run_id"] = values["parent_run"].id
extra = cast(dict, values.setdefault("extra", {}))
runtime = cast(dict, extra.setdefault("runtime", {}))
runtime.update(get_runtime_environment())
cast(dict, values.setdefault("extra", {}))
return values

def end(
Expand Down
Loading
Loading