Skip to content

Commit

Permalink
chore: add prometheus
Browse files Browse the repository at this point in the history
  • Loading branch information
RogerHYang committed Mar 19, 2024
1 parent cca0a0e commit 597ed93
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 5 deletions.
13 changes: 8 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This dockerfile is provided for convenience if you wish to run
# Phoenix in a docker container / sidecar.
# Phoenix in a docker container / sidecar.
# To use this dockerfile, you must first build the phoenix image
# using the following command:
# > docker build -t phoenix .
Expand All @@ -23,18 +23,21 @@ ADD . /phoenix


# Install the app by building the typescript package
RUN cd /phoenix/app && npm install && npm run build && rm -rf /phoenix/app
RUN cd /phoenix/app && npm install && npm run build && rm -rf /phoenix/app

FROM builder

# delete symbolic links
RUN find . -xtype l -delete

# Install any needed packages
RUN pip install .
# Install any needed packages
RUN pip install .[prometheus]

# Make port 6006 available to the world outside this container
EXPOSE 6006

# Prometheus
EXPOSE 9090

# Run server.py when the container launches
CMD ["python", "src/phoenix/server/main.py", "--host", "0.0.0.0", "--port", "6006", "serve"]
CMD ["python", "src/phoenix/server/main.py", "--host", "0.0.0.0", "--port", "6006", "--enable-prometheus", "True", "serve"]
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ llama-index = [
"llama-index-callbacks-arize-phoenix>=0.1.2",
"openinference-instrumentation-llama-index>=1.2.0",
]
prometheus = [
"prometheus-client",
]

[project.urls]
Documentation = "https://docs.arize.com/phoenix/"
Expand Down
8 changes: 8 additions & 0 deletions src/phoenix/server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def create_app(
span_store: Optional[SpanStore] = None,
debug: bool = False,
read_only: bool = False,
enable_prometheus: bool = False,
) -> Starlette:
graphql = GraphQLWithContext(
schema=schema,
Expand All @@ -160,9 +161,16 @@ def create_app(
export_path=export_path,
graphiql=True,
)
if enable_prometheus:
from phoenix.server.prometheus import PrometheusMiddleware

prometheus_middlewares = [Middleware(PrometheusMiddleware)]
else:
prometheus_middlewares = []
return Starlette(
middleware=[
Middleware(HeadersMiddleware),
*prometheus_middlewares,
],
debug=debug,
routes=(
Expand Down
6 changes: 6 additions & 0 deletions src/phoenix/server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def _load_items(
parser.add_argument("--no-internet", action="store_true")
parser.add_argument("--umap_params", type=str, required=False, default=DEFAULT_UMAP_PARAMS_STR)
parser.add_argument("--debug", action="store_false")
parser.add_argument("--enable-prometheus", type=bool, default=False)
subparsers = parser.add_subparsers(dest="command", required=True)
serve_parser = subparsers.add_parser("serve")
datasets_parser = subparsers.add_parser("datasets")
Expand Down Expand Up @@ -223,6 +224,10 @@ def _load_items(
)
read_only = args.read_only
logger.info(f"Server umap params: {umap_params}")
if enable_prometheus := args.enable_prometheus:
from phoenix.server.prometheus import start_prometheus

start_prometheus()
app = create_app(
export_path=export_path,
model=model,
Expand All @@ -232,6 +237,7 @@ def _load_items(
debug=args.debug,
read_only=read_only,
span_store=span_store,
enable_prometheus=enable_prometheus,
)
host = args.host or get_env_host()
port = args.port or get_env_port()
Expand Down
76 changes: 76 additions & 0 deletions src/phoenix/server/prometheus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import time
from threading import Thread

import psutil
from prometheus_client import (
Counter,
Gauge,
Histogram,
start_http_server,
)
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.requests import Request
from starlette.responses import Response
from starlette.routing import Match

REQUESTS_PROCESSING_TIME = Histogram(
name="starlette_requests_processing_time_seconds",
documentation="Histogram of requests processing time by method and path (in seconds)",
labelnames=["method", "path"],
)
EXCEPTIONS = Counter(
name="starlette_exceptions_total",
documentation="Total count of exceptions raised by method, path and exception type",
labelnames=["method", "path", "exception_type"],
)
RAM_METRIC = Gauge(
name="memory_usage_bytes",
documentation="Memory usage in bytes",
labelnames=["type"],
)
CPU_METRIC = Gauge(
name="cpu_usage_percent",
documentation="CPU usage percent",
labelnames=["core"],
)


class PrometheusMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
for route in request.app.routes:
match, _ = route.matches(request.scope)
if match is Match.FULL:
path = route.path
break
else:
return await call_next(request)
method = request.method
start_time = time.perf_counter()
try:
response = await call_next(request)
except BaseException as e:
EXCEPTIONS.labels(method=method, path=path, exception_type=type(e).__name__).inc()
raise
stop_time = time.perf_counter()
REQUESTS_PROCESSING_TIME.labels(method=method, path=path).observe(stop_time - start_time)
return response


def start_prometheus() -> None:
Thread(target=gather_system_data, daemon=True).start()
start_http_server(9090)


def gather_system_data() -> None:
while True:
time.sleep(1)

ram = psutil.virtual_memory()
swap = psutil.swap_memory()

RAM_METRIC.labels(type="virtual").set(ram.used)
RAM_METRIC.labels(type="swap").set(swap.used)

# Add cpu metrics
for c, p in enumerate(psutil.cpu_percent(interval=1, percpu=True)):
CPU_METRIC.labels(core=c).set(p)

0 comments on commit 597ed93

Please sign in to comment.