-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a728fa3
commit 47b9843
Showing
21 changed files
with
1,432 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
## ASGI Monitor | ||
[![license](https://img.shields.io/github/license/draincoder/asgi-monitor)](https://github.com/draincoder/asgi-monitor/blob/master/LICENSE) | ||
[![test](https://github.com/draincoder/asgi-monitor/actions/workflows/ci.yaml/badge.svg)](https://github.com/draincoder/asgi-monitor/actions/workflows/ci.yaml) | ||
[![PyPI version](https://badge.fury.io/py/asgi-monitor.svg)](https://pypi.python.org/pypi/asgi-monitor) | ||
[![Supported versions](https://img.shields.io/pypi/pyversions/asgi-monitor.svg)](https://pypi.python.org/pypi/asgi-monitor) | ||
[![downloads](https://img.shields.io/pypi/dm/asgi-monitor.svg)](https://pypistats.org/packages/asgi-monitor) | ||
|
||
A library for easy and fast configuration of logging, tracing and monitoring of ASGI applications. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
FROM python:3.10-slim-buster as python-base | ||
|
||
ENV PYTHONUNBUFFERED=1 \ | ||
PYTHONDONTWRITEBYTECODE=1 \ | ||
PIP_NO_CACHE_DIR=off \ | ||
PIP_DISABLE_PIP_VERSION_CHECK=on \ | ||
PIP_DEFAULT_TIMEOUT=100 \ | ||
PYSETUP_PATH="/opt/pysetup" \ | ||
VENV_PATH="/opt/pysetup/.venv" | ||
|
||
RUN python3 -m venv $VENV_PATH | ||
ENV PATH="$VENV_PATH/bin:$PATH" | ||
|
||
FROM python-base as builder-base | ||
RUN apt-get update && apt-get install -y gcc git | ||
|
||
WORKDIR $PYSETUP_PATH | ||
COPY requirements.txt . | ||
|
||
RUN pip install --no-cache-dir --upgrade pip \ | ||
&& pip install --no-cache-dir setuptools wheel \ | ||
&& pip install --no-cache-dir -r requirements.txt | ||
|
||
FROM python-base as production | ||
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH | ||
RUN apt-get update && apt-get install -y curl | ||
|
||
WORKDIR /app | ||
COPY ./app /app/app | ||
|
||
ENTRYPOINT ["python", "-Om", "app.main"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
## Start example in Docker | ||
|
||
```shell | ||
docker compose -f examples/real_world/docker-compose.yaml --profile api --profile grafana up --build -d | ||
``` | ||
|
||
## Stop example in Docker | ||
|
||
```shell | ||
docker compose -f examples/real_world/docker-compose.yaml --profile api --profile grafana down | ||
``` | ||
|
||
## Interfaces | ||
|
||
1. Grafana - http://127.0.0.1:3000/ | ||
2. Swagger - http://127.0.0.1:8080/docs/ |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import logging | ||
|
||
import uvicorn | ||
from fastapi import FastAPI | ||
from opentelemetry import trace | ||
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter | ||
from opentelemetry.sdk.resources import Resource | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import BatchSpanProcessor | ||
from asgi_monitor.integrations.fastapi import TracingConfig, setup_metrics, setup_tracing | ||
from asgi_monitor.logging import configure_logging | ||
from asgi_monitor.logging.uvicorn import build_uvicorn_log_config | ||
|
||
from app.routes import setup_routes | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
APP_NAME = "asgi-monitor" | ||
HOST = "0.0.0.0" | ||
PORT = 8080 | ||
GRPC_ENDPOINT = "http://asgi-monitor.tempo:4317" | ||
|
||
|
||
def create_app() -> FastAPI: | ||
configure_logging(level=logging.INFO, json_format=True) | ||
|
||
resource = Resource.create( | ||
attributes={ | ||
"service.name": APP_NAME, | ||
"compose_service": APP_NAME, | ||
}, | ||
) | ||
tracer = TracerProvider(resource=resource) | ||
trace.set_tracer_provider(tracer) | ||
tracer.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint=GRPC_ENDPOINT))) | ||
config = TracingConfig(tracer_provider=tracer) | ||
|
||
app = FastAPI(debug=True) | ||
setup_metrics(app, app_name=APP_NAME, include_trace_exemplar=True, include_metrics_endpoint=True) | ||
setup_tracing(app=app, config=config) | ||
setup_routes(app=app) | ||
|
||
return app | ||
|
||
|
||
if __name__ == "__main__": | ||
log_config = build_uvicorn_log_config( | ||
level=logging.INFO, | ||
json_format=True, | ||
include_trace=True, | ||
) | ||
uvicorn.run(create_app(), host=HOST, port=PORT, log_config=log_config) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from fastapi import FastAPI | ||
|
||
from .error import error_router | ||
from .healthcheck import healthcheck_router | ||
from .slow import slow_router | ||
|
||
__all__ = ("setup_routes",) | ||
|
||
|
||
def setup_routes(app: FastAPI) -> None: | ||
app.include_router(healthcheck_router) | ||
app.include_router(error_router) | ||
app.include_router(slow_router) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import logging | ||
|
||
from fastapi import APIRouter, status | ||
from fastapi.exceptions import HTTPException | ||
|
||
error_router = APIRouter( | ||
prefix="/error", | ||
tags=["Error"], | ||
include_in_schema=True, | ||
) | ||
logger = logging.getLogger(__name__) | ||
|
||
|
||
@error_router.get("/500", status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) | ||
async def get_500_error() -> None: | ||
logger.error("Internal Server Error Occurred", extra={"status_code": 500}) | ||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal Server Error") | ||
|
||
|
||
@error_router.get("/404", status_code=status.HTTP_404_NOT_FOUND) | ||
async def get_404() -> None: | ||
logger.error("Not Found", extra={"status_code": 404}) | ||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from fastapi import APIRouter, status | ||
|
||
healthcheck_router = APIRouter( | ||
prefix="/healthcheck", | ||
tags=["Healthcheck"], | ||
include_in_schema=True, | ||
) | ||
|
||
|
||
@healthcheck_router.get("/", status_code=status.HTTP_200_OK) | ||
async def get_status() -> dict: | ||
return {"message": "ok", "status": "success"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import asyncio | ||
import logging | ||
|
||
from fastapi import APIRouter, status | ||
from opentelemetry import trace | ||
|
||
slow_router = APIRouter( | ||
prefix="/slow", | ||
tags=["Slow"], | ||
include_in_schema=True, | ||
) | ||
logger = logging.getLogger(__name__) | ||
|
||
|
||
@slow_router.get("/1000ms", status_code=status.HTTP_200_OK) | ||
async def get_1000ms() -> dict: | ||
with trace.get_tracer("asgi-monitor").start_as_current_span("sleep 0.1"): | ||
await asyncio.sleep(0.1) | ||
with trace.get_tracer("asgi-monitor").start_as_current_span("sleep 0.2"): | ||
await asyncio.sleep(0.2) | ||
with trace.get_tracer("asgi-monitor").start_as_current_span("sleep 0.3"): | ||
await asyncio.sleep(0.3) | ||
with trace.get_tracer("asgi-monitor").start_as_current_span("sleep 0.4"): | ||
await asyncio.sleep(0.4) | ||
return {"message": "ok", "status": "success"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
version: "3.9" | ||
|
||
services: | ||
api: | ||
profiles: [ "api" ] | ||
container_name: asgi-monitor.api | ||
hostname: asgi-monitor.api | ||
build: | ||
context: . | ||
restart: unless-stopped | ||
expose: | ||
- "8080" | ||
ports: | ||
- "8080:8080" | ||
depends_on: | ||
tempo: | ||
condition: service_started | ||
networks: | ||
- asgi-monitor.grafana.network | ||
- asgi-monitor.api.network | ||
command: [ "python", "-Om", "app.main" ] | ||
healthcheck: | ||
test: [ "CMD-SHELL", "curl -fsSL http://localhost:8080/healthcheck" ] | ||
interval: 30s | ||
timeout: 60s | ||
retries: 5 | ||
start_period: 10s | ||
|
||
grafana: | ||
profiles: [ "grafana" ] | ||
image: grafana/grafana:latest | ||
container_name: asgi-monitor.grafana | ||
hostname: asgi-monitor.grafana | ||
restart: unless-stopped | ||
expose: | ||
- "3000" | ||
ports: | ||
- "127.0.0.1:3000:3000" | ||
networks: | ||
- asgi-monitor.grafana.network | ||
volumes: | ||
- asgi-monitor.grafana.data:/var/lib/grafana:rw | ||
- ./grafana/provisioning:/etc/grafana/provisioning:rw | ||
- ./grafana/dashboards:/etc/grafana/dashboards | ||
environment: | ||
- GF_SECURITY_ADMIN_USER=${GRAFANA_USER:-admin} | ||
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin} | ||
- GF_USERS_ALLOW_SIGN_UP=false | ||
- GF_DATABASE_WAL=true | ||
- VIRTUAL_HOST=crypto_trader.grafana | ||
- NETWORK_ACCESS=internal | ||
- VIRTUAL_PORT=3000 | ||
|
||
loki: | ||
profiles: [ "grafana" ] | ||
image: grafana/loki:2.7.3 | ||
container_name: asgi-monitor.loki | ||
hostname: asgi-monitor.loki | ||
expose: | ||
- "3100" | ||
volumes: | ||
- ./loki/config.yaml:/etc/loki/config.yaml:ro | ||
- asgi-monitor.loki.data:/tmp/:rw | ||
command: -config.file=/etc/loki/config.yaml | ||
restart: unless-stopped | ||
networks: | ||
- asgi-monitor.grafana.network | ||
|
||
vector: | ||
profiles: [ "grafana" ] | ||
image: timberio/vector:0.27.0-alpine | ||
container_name: asgi-monitor.vector | ||
hostname: asgi-monitor.vector | ||
restart: unless-stopped | ||
expose: | ||
- "8383" | ||
networks: | ||
- asgi-monitor.grafana.network | ||
volumes: | ||
- /var/run/docker.sock:/var/run/docker.sock:ro | ||
- ./vector/vector.toml:/etc/vector/vector.toml:ro | ||
logging: | ||
driver: "json-file" | ||
options: | ||
max-size: "10m" | ||
|
||
tempo: | ||
profiles: [ "grafana" ] | ||
image: grafana/tempo:2.0.1 | ||
container_name: asgi-monitor.tempo | ||
hostname: asgi-monitor.tempo | ||
command: [ "--target=all", "--storage.trace.backend=local", "--storage.trace.local.path=/var/tempo", "--auth.enabled=false" ] | ||
restart: unless-stopped | ||
ports: | ||
- "14250:14250" | ||
networks: | ||
- asgi-monitor.grafana.network | ||
depends_on: | ||
- loki | ||
|
||
prometheus: | ||
profiles: [ "grafana" ] | ||
image: prom/prometheus:latest | ||
container_name: asgi-monitor.prometheus | ||
hostname: asgi-monitor.prometheus | ||
restart: unless-stopped | ||
networks: | ||
- asgi-monitor.grafana.network | ||
volumes: | ||
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro | ||
- asgi-monitor.prometheus.data:/prometheus | ||
command: | ||
- --config.file=/etc/prometheus/prometheus.yml | ||
- --enable-feature=exemplar-storage | ||
ports: | ||
- "9090:9090" | ||
expose: | ||
- 9090 | ||
|
||
volumes: | ||
asgi-monitor.grafana.data: {} | ||
asgi-monitor.loki.data: {} | ||
asgi-monitor.prometheus.data: {} | ||
|
||
|
||
networks: | ||
asgi-monitor.api.network: {} | ||
asgi-monitor.grafana.network: {} |
Oops, something went wrong.