diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8fa9bca --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Flask with middleware-run", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/flask/flaskenv/bin/flask", + "args": [ + "run", + "--no-reload" + ], + "env": { + "FLASK_APP": "${workspaceFolder}/flask/app.py", // adjust if your app entry point is different + "FLASK_ENV": "development", + "MW_SERVICE_NAME": "flask-demo-apps", + "PATH": "${workspaceFolder}/flask/flaskenv/bin", + "DEBUG_MODE": "1" + }, + "cwd": "${workspaceFolder}/flask", + "console": "integratedTerminal", + "justMyCode": false, + "python": "${workspaceFolder}/flask/flaskenv/bin/python3", + "subProcess": true + } + ] + } + \ No newline at end of file diff --git a/Flask-O-shop b/Flask-O-shop new file mode 160000 index 0000000..d439c4a --- /dev/null +++ b/Flask-O-shop @@ -0,0 +1 @@ +Subproject commit d439c4a50d10d0c51820db3422f9197d298ead5e diff --git a/django/django_uwsgi_nginx/django_uwsgi_nginx_wsgi.py b/django/django_uwsgi_nginx/django_uwsgi_nginx_wsgi.py index ffda53e..95d3bd6 100755 --- a/django/django_uwsgi_nginx/django_uwsgi_nginx_wsgi.py +++ b/django/django_uwsgi_nginx/django_uwsgi_nginx_wsgi.py @@ -1,5 +1,12 @@ import os from django.core.wsgi import get_wsgi_application +from uwsgidecorators import postfork +from middleware import mw_tracker, MWOptions, record_exception, DETECT_AWS_EC2 + +@postfork +def tracing(): + mw_tracker() os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_uwsgi_nginx_settings') application = get_wsgi_application() + diff --git a/django/django_uwsgi_nginx_otel/Dockerfile b/django/django_uwsgi_nginx_otel/Dockerfile new file mode 100755 index 0000000..ff2a28e --- /dev/null +++ b/django/django_uwsgi_nginx_otel/Dockerfile @@ -0,0 +1,24 @@ +FROM python:3.10 +WORKDIR /app +COPY requirements.txt . +RUN pip install -r requirements.txt +COPY . . +ENV DJANGO_SETTINGS_MODULE=django_uwsgi_nginx_settings +RUN ls -l /app && python manage.py collectstatic --noinput + +# replace with your Middleware API key +ENV MW_API_KEY="whkvkobudfitutobptgonaezuxpjjypnejbb" + +# replace with your Middleware App name +ENV MW_SERVICE_NAME="MyPythonApp" + +# replace with your Middleware App url for serverless +ENV MW_TARGET="https://myapp.middleware.io:443" + +# enable Middleware Console Exporter for logs and debug +ENV MW_CONSOLE_EXPORTER=True +ENV MW_DEBUG_LOG_FILE=True +ENV MW_LOG_LEVEL=DEBUG + +# attach middleware-run to the entrypoint for instrumentation +CMD ["middleware-run","uwsgi", "--http", ":8000", "--module", "django_uwsgi_nginx_wsgi", "--static-map", "/static=/static"] diff --git a/django/django_uwsgi_nginx_otel/README.md b/django/django_uwsgi_nginx_otel/README.md new file mode 100644 index 0000000..871d1e3 --- /dev/null +++ b/django/django_uwsgi_nginx_otel/README.md @@ -0,0 +1,56 @@ +# Django Application with uWSGI, Nginx, and Middleware Integration Guide + +This project demonstrates how to set up a **Django** application with **uWSGI** and **Nginx**, along with **Middleware** integration for Application Performance Monitoring (APM). + +Follow the [Middleware APM setup documentation](https://docs.middleware.io/docs/apm-configuration/python/python-apm-setup) to integrate APM with your Django application. + +[![PyPI - Version](https://img.shields.io/pypi/v/middleware-io)](https://pypi.org/project/middleware-io/) + +| Traces | Metrics | Profiling | Logs (App/Custom) | +|:------:|:-------:|:---------:|:-----------------:| +| Yes | Yes | Yes | Yes/Yes | + +## Prerequisites + +Before running the project, ensure you have the **Middleware Host Agent** installed to view Python demo data on your dashboard. + +--- + +## Steps to Run the Project + +Create and Activate Virtual Environment: + +```python +python3 -m venv env +source env/bin/activate +``` + +Install Dependencies + +``` +pip install -r requirements.txt +``` + +Install OpenTelemetry instrument libraries + +```python +middleware-bootstrap -a install +``` + +Run the Application + +``` +docker compose up --build +``` + +Command for App Instrumentation + +```python +DJANGO_SETTINGS_MODULE="django_uwsgi_nginx_settings" middleware-run uwsgi --http :8000 --module django_uwsgi_nginx_wsgi --static-map /static=/static +``` + +If you are running this application in a serverless setup consider adding `MW_API_KEY` and `MW_TARGET` as mentioned in the command below : + +```python +MW_API_KEY=********** MW_TARGET=https://*****.middleware.io:443 DJANGO_SETTINGS_MODULE="django_uwsgi_nginx_settings" middleware-run uwsgi --http :8000 --module django_uwsgi_nginx_wsgi --static-map /static=/static +``` \ No newline at end of file diff --git a/django/django_uwsgi_nginx_otel/django_uwsgi_nginx_settings.py b/django/django_uwsgi_nginx_otel/django_uwsgi_nginx_settings.py new file mode 100755 index 0000000..25222c0 --- /dev/null +++ b/django/django_uwsgi_nginx_otel/django_uwsgi_nginx_settings.py @@ -0,0 +1,36 @@ +SECRET_KEY = 'replace-with-a-secure-key' +DEBUG = True +ALLOWED_HOSTS = ['*'] +ROOT_URLCONF = 'django_uwsgi_nginx_urls' +WSGI_APPLICATION = 'django_uwsgi_nginx_wsgi.application' + +INSTALLED_APPS = [ + 'django.contrib.contenttypes', + 'django.contrib.staticfiles', + 'sample_app', +] + +MIDDLEWARE = [ + 'django.middleware.common.CommonMiddleware', +] + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [], + }, + }, +] + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'db.sqlite3', + } +} + +STATIC_URL = '/static/' +STATIC_ROOT = '/static/' diff --git a/django/django_uwsgi_nginx_otel/django_uwsgi_nginx_urls.py b/django/django_uwsgi_nginx_otel/django_uwsgi_nginx_urls.py new file mode 100755 index 0000000..5d9b6ba --- /dev/null +++ b/django/django_uwsgi_nginx_otel/django_uwsgi_nginx_urls.py @@ -0,0 +1,5 @@ +from django.urls import path, include + +urlpatterns = [ + path('', include('sample_app.urls')), +] diff --git a/django/django_uwsgi_nginx_otel/django_uwsgi_nginx_wsgi.py b/django/django_uwsgi_nginx_otel/django_uwsgi_nginx_wsgi.py new file mode 100755 index 0000000..9c14905 --- /dev/null +++ b/django/django_uwsgi_nginx_otel/django_uwsgi_nginx_wsgi.py @@ -0,0 +1,26 @@ +import os +from django.core.wsgi import get_wsgi_application + +from uwsgidecorators import postfork + +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 + +@postfork +def init_tracing(): + resource = Resource.create(attributes={ + "service.name": "django-uwsgi-otel" + }) + + trace.set_tracer_provider(TracerProvider(resource=resource)) + span_processor = BatchSpanProcessor( + OTLPSpanExporter(endpoint="http://localhost:9319") + ) + trace.get_tracer_provider().add_span_processor(span_processor) + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_uwsgi_nginx_settings') +application = get_wsgi_application() + diff --git a/django/django_uwsgi_nginx_otel/docker-compose.yml b/django/django_uwsgi_nginx_otel/docker-compose.yml new file mode 100755 index 0000000..7e28063 --- /dev/null +++ b/django/django_uwsgi_nginx_otel/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3.8' + +services: + django: + build: . + volumes: + - ./static:/static + ports: + - "8000:8000" + + nginx: + image: nginx:latest + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + - ./static:/static + ports: + - "8080:80" + depends_on: + - django diff --git a/django/django_uwsgi_nginx_otel/manage.py b/django/django_uwsgi_nginx_otel/manage.py new file mode 100755 index 0000000..468980c --- /dev/null +++ b/django/django_uwsgi_nginx_otel/manage.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_uwsgi_nginx_settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) diff --git a/django/django_uwsgi_nginx_otel/nginx.conf b/django/django_uwsgi_nginx_otel/nginx.conf new file mode 100755 index 0000000..34e58da --- /dev/null +++ b/django/django_uwsgi_nginx_otel/nginx.conf @@ -0,0 +1,21 @@ +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + server { + listen 80; + + location /static/ { + alias /static/; + } + + location / { + proxy_pass http://django:8000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + } +} diff --git a/django/django_uwsgi_nginx_otel/requirements.txt b/django/django_uwsgi_nginx_otel/requirements.txt new file mode 100755 index 0000000..661524d --- /dev/null +++ b/django/django_uwsgi_nginx_otel/requirements.txt @@ -0,0 +1,4 @@ +django +uwsgi +opentelemetry-distro +opentelemetry-exporter-otlp \ No newline at end of file diff --git a/django/django_uwsgi_nginx_otel/sample_app/__init__.py b/django/django_uwsgi_nginx_otel/sample_app/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/django/django_uwsgi_nginx_otel/sample_app/migrations/__init__.py b/django/django_uwsgi_nginx_otel/sample_app/migrations/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/django/django_uwsgi_nginx_otel/sample_app/templates/index.html b/django/django_uwsgi_nginx_otel/sample_app/templates/index.html new file mode 100755 index 0000000..4e3355c --- /dev/null +++ b/django/django_uwsgi_nginx_otel/sample_app/templates/index.html @@ -0,0 +1,19 @@ + + + + Sample Page + + +

Welcome to the Django Sample App

+ +

+ + + + diff --git a/django/django_uwsgi_nginx_otel/sample_app/urls.py b/django/django_uwsgi_nginx_otel/sample_app/urls.py new file mode 100755 index 0000000..3aae56f --- /dev/null +++ b/django/django_uwsgi_nginx_otel/sample_app/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from .views import api_endpoint, html_page, raise_exception + +urlpatterns = [ + path('api/', api_endpoint, name='api'), + path('page/', html_page, name='html_page'), + path('error/', raise_exception, name='raise_exception'), +] diff --git a/django/django_uwsgi_nginx_otel/sample_app/views.py b/django/django_uwsgi_nginx_otel/sample_app/views.py new file mode 100755 index 0000000..1f16624 --- /dev/null +++ b/django/django_uwsgi_nginx_otel/sample_app/views.py @@ -0,0 +1,11 @@ +from django.http import JsonResponse +from django.shortcuts import render + +def api_endpoint(request): + return JsonResponse({"message": "Hello from the API!"}) + +def html_page(request): + return render(request, "index.html") + +def raise_exception(request): + raise ValueError("This is a sample exception!") diff --git a/fastapi/uvicorn/main.py b/fastapi/uvicorn/main.py index 7e40049..1a5eace 100644 --- a/fastapi/uvicorn/main.py +++ b/fastapi/uvicorn/main.py @@ -1,40 +1,51 @@ import logging +import os +from typing import Union +from fastapi import FastAPI, HTTPException +from dotenv import load_dotenv from middleware import mw_tracker, MWOptions -mw_tracker( - MWOptions( - access_token="whkvkobudfitutobptgonaezuxpjjypnejbb", - target="https://myapp.middleware.io:443", - service_name="MyPythonApp", - ) -) - -from dotenv import load_dotenv +# Load environment variables load_dotenv() -import os - -from typing import Union - -from fastapi import FastAPI +# Initialize FastAPI app app = FastAPI() +# Set logging level logging.getLogger().setLevel(logging.INFO) +# Sample APIs @app.get("/") def read_root(): - logging.info("Hello World") - return {"Hello": "World"} - + logging.info("Root API accessed") + return {"message": "Welcome to the API"} @app.get("/items/{item_id}") def read_item(item_id: int, q: Union[str, None] = None): logging.debug("Item ID: %s", item_id) - return {"item_id": item_id, "q": q} + return {"item_id": item_id, "query": q} + +@app.post("/create") +def create_item(name: str, price: float): + logging.info("Item created: %s", name) + return {"name": name, "price": price} +@app.put("/update/{item_id}") +def update_item(item_id: int, name: str): + logging.info("Item updated: %d", item_id) + return {"item_id": item_id, "updated_name": name} + +@app.delete("/delete/{item_id}") +def delete_item(item_id: int): + logging.info("Item deleted: %d", item_id) + return {"message": f"Item {item_id} deleted"} + +@app.get("/error") +def generate_error(): + logging.error("Error generated") + raise HTTPException(status_code=500, detail="Simulated error") if __name__ == "__main__": import uvicorn - - uvicorn.run('main:app', reload=True) \ No newline at end of file + uvicorn.run(app, host="127.0.0.1", port=5002, reload=True) diff --git a/fastapi/uvicorn/requirements.txt b/fastapi/uvicorn/requirements.txt index d93769c..ca31b98 100644 --- a/fastapi/uvicorn/requirements.txt +++ b/fastapi/uvicorn/requirements.txt @@ -1,4 +1,5 @@ -middleware-io>=2.0.0 +middleware-io==2.1.0 fastapi==0.115.5 uvicorn==0.32.0 -python-dotenv=1.0.1 \ No newline at end of file +python-dotenv==1.0.1 +httpx==0.20.0 \ No newline at end of file diff --git a/flask/Dockerfile b/flask/Dockerfile index ac7b809..13db86a 100644 --- a/flask/Dockerfile +++ b/flask/Dockerfile @@ -4,30 +4,16 @@ FROM python:3.11-slim-bullseye as base -# -# Fetch requirements -# -FROM base as builder RUN apt-get -qq update \ && apt-get install -y --no-install-recommends g++ \ && rm -rf /var/lib/apt/lists/* WORKDIR /usr/src/app/ COPY ./requirements.txt ./ - -RUN pip install --upgrade pip -RUN pip install --prefix="/reqs" -r requirements.txt -# -# Runtime -# -FROM base as runtime -WORKDIR /usr/src/app/ -COPY --from=builder /reqs /usr/local COPY ./ ./ - -# Setup ENV variables -ENV MW_AGENT_SERVICE=172.17.0.1 - +RUN pip install --upgrade pip +RUN pip install -r requirements.txt +RUN pip install middleware-io==2.1.2rc16 RUN middleware-bootstrap -a install -ENTRYPOINT [ "middleware-run", "python", "app.py" ] \ No newline at end of file +ENTRYPOINT [ "middleware-run", "flask", "run" ] \ No newline at end of file diff --git a/flask/app.py b/flask/app.py index 81ded80..cc5dc4f 100644 --- a/flask/app.py +++ b/flask/app.py @@ -1,15 +1,17 @@ from middleware import mw_tracker, MWOptions -mw_tracker( - MWOptions( - access_token="whkvkobudfitutobptgonaezuxpjjypnejbb", - target="https://myapp.middleware.io:443", - service_name="MyPythonApp", - ) -) +# mw_tracker( +# MWOptions( +# access_token="whkvkobudfitutobptgonaezuxpjjypnejbb", +# target="https://myapp.middleware.io:443", +# service_name="MyPythonApp", +# ) +# ) from flask import Flask import logging +import sys +from test import sample_function, another_function logging.getLogger().setLevel(logging.INFO) logging.info("Application initiated successfully.", extra={'Tester': 'Alex'}) @@ -22,19 +24,10 @@ def hello_world(): logging.info("info log sample") return 'Hello World!' -@app.route('/exception') +@app.route('/exception-new') def generate_exception(): - randomList = ['a', 0, 2] - - for entry in randomList: - try: - print("The entry is", entry) - r = 1/int(entry) - break - except Exception as e: - tracker.record_error(e) - print("The reciprocal of", entry, "is", r) - return 'Exception Generated!' + print("Exception generated ......") + sample_function() if __name__ == '__main__': - app.run('0.0.0.0', 8010) + app.run('0.0.0.0', 8010) \ No newline at end of file diff --git a/flask/docker-compose.yaml b/flask/docker-compose.yaml new file mode 100644 index 0000000..2e0c028 --- /dev/null +++ b/flask/docker-compose.yaml @@ -0,0 +1,10 @@ +services: + flask-app: + build: . + # image: ghcr.io/middleware-labs/demo-apm-python:AGE-148 + ports: + - "5000:5000" + environment: + - MW_SERVICE_NAME=test-service + - MW_API_KEY=mgqjtlgshkyhlykoaermkzbjpmgprkrzmbsb + - MW_TARGET=https://sbncr.stage.env.middleware.io:443 \ No newline at end of file diff --git a/flask/requirements.txt b/flask/requirements.txt index f9c8d14..19acec6 100644 --- a/flask/requirements.txt +++ b/flask/requirements.txt @@ -1,2 +1 @@ -middleware-io>=2.0.0 flask==2.3.2 \ No newline at end of file diff --git a/flask/test.py b/flask/test.py new file mode 100644 index 0000000..18cd9b1 --- /dev/null +++ b/flask/test.py @@ -0,0 +1,3 @@ +import sys +def sample_function(): + 1/0 \ No newline at end of file diff --git a/github-ai-testing/social-media-blog-backend b/github-ai-testing/social-media-blog-backend new file mode 160000 index 0000000..d2a88b3 --- /dev/null +++ b/github-ai-testing/social-media-blog-backend @@ -0,0 +1 @@ +Subproject commit d2a88b37a8278895e15bc1d56ca4fd59e7a97669 diff --git a/github-ai-testing/social-media-blog-frontend b/github-ai-testing/social-media-blog-frontend new file mode 160000 index 0000000..d0511db --- /dev/null +++ b/github-ai-testing/social-media-blog-frontend @@ -0,0 +1 @@ +Subproject commit d0511dba4af437fd1552834a247d6f022a340121