├── .github └── workflows │ ├── lint.yml │ └── test-genai-function-calling.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CODEOWNERS ├── Elastiflix ├── .env ├── .gitignore ├── Makefile ├── README.md ├── docker-compose-elastic-otel.yml ├── docker-compose-elastic.yml ├── docker-compose.yml ├── dotnet-login-elastic-auto │ ├── Controllers │ │ └── LoginController.cs │ ├── Dockerfile │ ├── Dockerfile.elastic.apm.profiler │ ├── Dockerfile.elasticagent │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.json │ ├── login.csproj │ └── login.sln ├── dotnet-login-elastic-manual │ ├── Controllers │ │ └── LoginController.cs │ ├── Dockerfile │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.json │ ├── login.csproj │ └── login.sln ├── dotnet-login-otel-auto │ ├── Controllers │ │ └── LoginController.cs │ ├── Dockerfile │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.json │ ├── login.csproj │ ├── login.sln │ └── platform-detection.sh ├── dotnet-login-otel-manual │ ├── Controllers │ │ └── LoginController.cs │ ├── Dockerfile │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── Telemetry.cs │ ├── appsettings.json │ ├── login.csproj │ └── login.sln ├── dotnet-login │ ├── Controllers │ │ └── LoginController.cs │ ├── Dockerfile │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.json │ ├── login.csproj │ └── login.sln ├── go-favorite-elastic-manual │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ └── main.go ├── go-favorite-otel-manual │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ └── main.go ├── go-favorite │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ └── main.go ├── java-favorite-elastic-auto │ ├── Dockerfile │ ├── pom.xml │ ├── src │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── movieapi │ │ │ │ ├── ApiServlet.java │ │ │ │ └── FavoriteApplication.java │ │ │ └── resources │ │ │ ├── application.properties │ │ │ └── logback.xml │ └── start.sh ├── java-favorite-elastic-manual │ ├── Dockerfile │ ├── pom.xml │ ├── src │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── movieapi │ │ │ │ ├── ApiServlet.java │ │ │ │ └── FavoriteApplication.java │ │ │ └── resources │ │ │ ├── application.properties │ │ │ └── logback.xml │ └── start.sh ├── java-favorite-otel-auto │ ├── Dockerfile │ ├── pom.xml │ ├── src │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── movieapi │ │ │ │ ├── ApiServlet.java │ │ │ │ └── FavoriteApplication.java │ │ │ └── resources │ │ │ ├── application.properties │ │ │ └── logback.xml │ └── start.sh ├── java-favorite-otel-manual │ ├── Dockerfile │ ├── pom.xml │ ├── src │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── movieapi │ │ │ │ ├── ApiServlet.java │ │ │ │ ├── FavoriteApplication.java │ │ │ │ └── TracingFilter.java │ │ │ └── resources │ │ │ ├── application.properties │ │ │ └── logback.xml │ └── start.sh ├── java-favorite │ ├── Dockerfile │ ├── pom.xml │ ├── src │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── movieapi │ │ │ │ ├── ApiServlet.java │ │ │ │ └── FavoriteApplication.java │ │ │ └── resources │ │ │ ├── application.properties │ │ │ └── logback.xml │ └── start.sh ├── javascript-client-elastic-manual │ ├── .env │ ├── .nvmrc │ ├── Dockerfile │ ├── nginx │ │ └── nginx.conf │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── icon.svg │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── scripts │ │ └── docker-entrypoint.sh │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── coming-soon.png │ │ ├── components │ │ │ ├── Card.js │ │ │ ├── Header.js │ │ │ ├── Home.js │ │ │ ├── Layout.js │ │ │ ├── MultiCheckboxFacet.js │ │ │ ├── Nav.js │ │ │ ├── Popular.js │ │ │ ├── Recent.js │ │ │ ├── Results.js │ │ │ ├── Routes.js │ │ │ ├── SearchBar.js │ │ │ └── SearchPage.js │ │ ├── index.js │ │ ├── index.scss │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ ├── setupTests.js │ │ └── tmdb-logo.svg │ ├── static │ │ ├── create-deployment.gif │ │ ├── get-as-settings.gif │ │ ├── get-cloud-id.gif │ │ ├── loader │ │ │ └── get_as_base_url.gif │ │ └── ui │ │ │ └── ui.png │ └── yarn.lock ├── javascript-client │ ├── .env │ ├── .nvmrc │ ├── Dockerfile │ ├── nginx │ │ └── nginx.conf │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── icon.svg │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── scripts │ │ └── docker-entrypoint.sh │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── coming-soon.png │ │ ├── components │ │ │ ├── Card.js │ │ │ ├── Header.js │ │ │ ├── Home.js │ │ │ ├── Layout.js │ │ │ ├── MultiCheckboxFacet.js │ │ │ ├── Nav.js │ │ │ ├── Popular.js │ │ │ ├── Recent.js │ │ │ ├── Results.js │ │ │ ├── Routes.js │ │ │ ├── SearchBar.js │ │ │ └── SearchPage.js │ │ ├── index.js │ │ ├── index.scss │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ ├── setupTests.js │ │ └── tmdb-logo.svg │ ├── static │ │ ├── create-deployment.gif │ │ ├── get-as-settings.gif │ │ ├── get-cloud-id.gif │ │ ├── loader │ │ │ └── get_as_base_url.gif │ │ └── ui │ │ │ └── ui.png │ └── yarn.lock ├── locustfile.py ├── movie-data-loader │ ├── .nvmrc │ ├── Dockerfile │ ├── index.js │ ├── mapping.json │ ├── movies.json.gz │ ├── package-lock.json │ └── package.json ├── node-server-elastic-manual │ ├── .nvmrc │ ├── Dockerfile │ ├── index.js │ ├── package-lock.json │ └── package.json ├── node-server-otel-auto │ ├── .nvmrc │ ├── Dockerfile │ ├── index.js │ ├── package-lock.json │ └── package.json ├── node-server-otel-manual │ ├── .nvmrc │ ├── Dockerfile │ ├── index.js │ ├── package-lock.json │ └── package.json ├── node-server │ ├── .nvmrc │ ├── Dockerfile │ ├── index.js │ ├── package-lock.json │ └── package.json ├── otel-config-extras.yml ├── otel-config.yml ├── properties.json ├── python-favorite-elastic-manual │ ├── Dockerfile │ ├── main.py │ └── requirements.txt ├── python-favorite-otel-auto │ ├── Dockerfile │ ├── main.py │ └── requirements.txt ├── python-favorite-otel-manual │ ├── Dockerfile │ ├── locustfile.py │ ├── main.py │ └── requirements.txt ├── python-favorite │ ├── Dockerfile │ ├── main.py │ └── requirements.txt ├── redis │ ├── Dockerfile │ └── entrypoint.sh └── screenshots │ ├── frontend.png │ ├── inventory.png │ └── service-map.png ├── LICENSE ├── Makefile ├── README.md ├── anomaly-detection ├── README.md ├── generate-transactions.js └── package.json ├── aws └── app-runner │ ├── README.md │ ├── helloworld-observe │ ├── Dockerfile │ ├── helloworld.py │ └── requirements.txt │ └── helloworld │ ├── Dockerfile │ ├── helloworld.py │ └── requirements.txt ├── azure └── container-apps │ ├── Readme.md │ ├── helloworld-observe │ ├── Dockerfile │ ├── Program.cs │ ├── Telemetry.cs │ └── helloworld.csproj │ └── helloworld │ ├── Dockerfile │ ├── Program.cs │ └── helloworld.csproj ├── chatbot-rag-app-observability ├── README.md ├── init-index-job.yaml └── k8s-deployment-chatbot-rag-app.yaml ├── gcp └── run │ ├── README.md │ ├── helloworld-observe │ ├── Dockerfile │ ├── index.js │ └── package.json │ └── helloworld │ ├── Dockerfile │ ├── index.js │ └── package.json ├── genai-function-calling ├── README.md ├── kibana-trace.png ├── openai-agents │ ├── Dockerfile │ ├── README.md │ ├── cassettes │ │ └── test_main.yaml │ ├── conftest.py │ ├── docker-compose.yml │ ├── env.example │ ├── main.py │ ├── main_mcp.py │ ├── main_test.py │ ├── pytest.ini │ ├── requirements-dev.txt │ └── requirements.txt ├── semantic-kernel-dotnet │ ├── .dockerignore │ ├── Dockerfile │ ├── Program.cs │ ├── README.md │ ├── app.csproj │ ├── docker-compose.yml │ └── env.example ├── spring-ai │ ├── .mvn │ │ └── wrapper │ │ │ └── maven-wrapper.properties │ ├── Dockerfile │ ├── README.md │ ├── docker-compose.yml │ ├── env.example │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── example │ │ │ ├── ElasticsearchTools.java │ │ │ ├── Main.java │ │ │ ├── Mcp.java │ │ │ └── VersionAgent.java │ │ └── resources │ │ └── application.yml └── vercel-ai │ ├── .dockerignore │ ├── .npmrc │ ├── Dockerfile │ ├── README.md │ ├── docker-compose.yml │ ├── env.example │ ├── index.js │ ├── mcp.js │ ├── package.json │ └── telemetry.js ├── inference-platforms ├── README.md ├── archgw │ ├── README.md │ ├── arch_config.yaml │ ├── docker-compose-elastic.yml │ └── env.local ├── chat.py ├── kibana-trace.jpg ├── litellm │ ├── Dockerfile │ ├── README.md │ ├── config.yaml │ ├── docker-compose.yml │ └── env.local ├── llama-stack │ ├── README.md │ ├── docker-compose.yml │ └── env.local ├── open-responses │ ├── README.md │ ├── docker-compose.yml │ └── env.local └── vllm │ ├── Dockerfile │ ├── README.md │ ├── docker-compose.yml │ └── env.local ├── langchainChat ├── ENV ├── img │ ├── SCR-20240816-icwt-2.png │ └── Xnapper-2024-08-16-12.36.03.png ├── langtrace-elastic-demo-readme.md ├── langtrace-elastic-demo.py └── requirements.txt └── lychee.toml /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | lint: 10 | runs-on: ubuntu-24.04 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Set up Python 3.12 14 | uses: actions/setup-python@v5 15 | with: 16 | python-version: 3.12 17 | - name: Install pre-commit 18 | run: | 19 | python -m pip install --upgrade pip 20 | pip install pre-commit 21 | - run: make lint 22 | -------------------------------------------------------------------------------- /.github/workflows/test-genai-function-calling.yml: -------------------------------------------------------------------------------- 1 | name: test-genai-function-calling 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | paths: 8 | - 'genai-function-calling/openai-agents/**' 9 | - '!**/*.md' 10 | - '!**/*.png' 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Set up Python 3.12 19 | uses: actions/setup-python@v5 20 | with: 21 | python-version: 3.12 22 | 23 | - name: openai-agents 24 | run: | 25 | pip install -r requirements.txt 26 | pip install -r requirements-dev.txt 27 | pytest --vcr-record=none 28 | working-directory: genai-function-calling/openai-agents 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .envrc 3 | .idea 4 | node_modules 5 | .vscode 6 | venv 7 | .venv 8 | tmp 9 | *.swp 10 | *.egg-info 11 | build 12 | __pycache__ 13 | .gradle 14 | .nyc_output 15 | *.sln 16 | 17 | # dotnet 18 | out 19 | obj 20 | bin 21 | 22 | # maven 23 | target 24 | 25 | ### Mac OS ### 26 | .DS_Store 27 | 28 | # Alternative Python package managers like rye 29 | requirements*.lock 30 | 31 | shdotenv 32 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_language_version: 2 | python: python3.12 3 | repos: 4 | - repo: https://github.com/astral-sh/ruff-pre-commit 5 | rev: v0.11.0 6 | hooks: 7 | - id: ruff 8 | args: [ 9 | "--fix", 10 | "--line-length", "120", 11 | "--extend-select=PLC,PLE,Q,A", 12 | ] 13 | - id: ruff-format 14 | args: [ 15 | "--line-length", "120" 16 | ] 17 | 18 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | genai-function-calling/ @codefromthecrypt @anuraaga 2 | inference-platforms/ @codefromthecrypt @anuraaga 3 | -------------------------------------------------------------------------------- /Elastiflix/.env: -------------------------------------------------------------------------------- 1 | ELASTIC_APM_SERVER_URL="https://foobar.apm.us-central1.gcp.cloud.es.io" 2 | ELASTIC_APM_SECRET_TOKEN="secret123" 3 | 4 | ELASTICSEARCH_USERNAME="elastic" 5 | ELASTICSEARCH_PASSWORD="changeme" 6 | ELASTICSEARCH_URL="https://foobar.es.us-central1.gcp.cloud.es.io" 7 | 8 | BUILD_NUMBER="10" 9 | ELASTIC_VERSION="8.9.0" 10 | -------------------------------------------------------------------------------- /Elastiflix/.gitignore: -------------------------------------------------------------------------------- 1 | src/streaming-ui/scripts/.env-debug 2 | src/data-loader/env-debug 3 | node_modules/ 4 | **/.venv 5 | */bin/Debug 6 | **__pycache__ 7 | .env 8 | **/.idea 9 | dotnet*/obj 10 | .idea 11 | 12 | # maven target folder 13 | java-favorite-elastic-auto/target 14 | java-favorite-elastic-manual/target 15 | java-favorite-otel-auto/target 16 | java-favorite-otel-manual/target 17 | java-favorite/target 18 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/Controllers/LoginController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Serilog; 5 | 6 | namespace login.Controllers 7 | { 8 | [ApiController] 9 | [Route("[controller]")] 10 | public class LoginController : ControllerBase 11 | { 12 | private static readonly List UserNames = new List 13 | { 14 | "Alice", 15 | "Bob", 16 | "Charlie", 17 | "Dave", 18 | "Eva" 19 | }; 20 | 21 | // Responds to GET requests. 22 | [HttpGet] 23 | public ActionResult Get() 24 | { 25 | var user = GenerateRandomUserResponse(); 26 | Log.Information("User logged in: {UserName}", user); 27 | return user; 28 | } 29 | 30 | // Responds to POST requests. 31 | [HttpPost] 32 | public ActionResult Post([FromBody] dynamic body) 33 | { 34 | // This is just an example, you might want to do something with the posted data. 35 | var user = GenerateRandomUserResponse(); 36 | Log.Information("User logged in: {UserName}", user); 37 | return user; 38 | } 39 | 40 | private ActionResult GenerateRandomUserResponse() 41 | { 42 | var random = new Random(); 43 | var index = random.Next(UserNames.Count); 44 | return Ok(new { userName = UserNames[index] }); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ${ARCH}mcr.microsoft.com/dotnet/aspnet:7.0. AS base 2 | WORKDIR /app 3 | EXPOSE 8000 4 | 5 | FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build 6 | WORKDIR /src 7 | COPY ["login.csproj", "./"] 8 | RUN dotnet restore "./login.csproj" 9 | COPY . . 10 | WORKDIR "/src/." 11 | RUN dotnet build "login.csproj" -c Release -o /app/build 12 | 13 | FROM build AS publish 14 | RUN dotnet publish "login.csproj" -c Release -o /app/publish 15 | 16 | FROM base AS final 17 | WORKDIR /app 18 | COPY --from=publish /app/publish . 19 | 20 | ARG AGENT_VERSION=1.22.0 21 | 22 | RUN apt-get update && apt-get install -y zip curl 23 | RUN curl -L -o ElasticApmAgent_${AGENT_VERSION}.zip https://github.com/elastic/apm-agent-dotnet/releases/download/v${AGENT_VERSION}/ElasticApmAgent_${AGENT_VERSION}.zip && unzip ElasticApmAgent_${AGENT_VERSION}.zip -d /elastic_apm_agent 24 | 25 | ENV DOTNET_STARTUP_HOOKS=/elastic_apm_agent/ElasticApmAgentStartupHook.dll 26 | ENV ELASTIC_APM_SERVICE_NAME=dotNetLoginService 27 | ENV ELASTIC_APM_ENVIRONMENT=production 28 | 29 | ENTRYPOINT ["dotnet", "login.dll"] 30 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/Dockerfile.elastic.apm.profiler: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base 2 | WORKDIR /app 3 | EXPOSE 8000 4 | 5 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 6 | WORKDIR /src 7 | COPY ["login.csproj", "./"] 8 | RUN dotnet restore "./login.csproj" 9 | COPY . . 10 | WORKDIR "/src/." 11 | RUN dotnet build "login.csproj" -c Release -o /app/build 12 | 13 | FROM build AS publish 14 | RUN dotnet publish "login.csproj" -c Release -o /app/publish 15 | 16 | FROM base AS final 17 | WORKDIR /app 18 | COPY --from=publish /app/publish . 19 | 20 | ARG AGENT_VERSION=1.22.0 21 | 22 | RUN apt-get update && apt-get install -y zip curl 23 | RUN curl -L -o elastic_apm_profiler_${AGENT_VERSION}-linux-x64.zip https://github.com/elastic/apm-agent-dotnet/releases/download/v${AGENT_VERSION}/elastic_apm_profiler_${AGENT_VERSION}-linux-x64.zip && \ 24 | unzip elastic_apm_profiler_${AGENT_VERSION}-linux-x64.zip -d /elastic_apm_profiler 25 | 26 | ENV CORECLR_ENABLE_PROFILING=1 27 | ENV CORECLR_PROFILER={FA65FE15-F085-4681-9B20-95E04F6C03CC} 28 | ENV CORECLR_PROFILER_PATH=/elastic_apm_profiler/libelastic_apm_profiler.so 29 | ENV ELASTIC_APM_PROFILER_HOME=/elastic_apm_profiler 30 | ENV ELASTIC_APM_PROFILER_INTEGRATIONS=/elastic_apm_profiler/integrations.yml 31 | ENV ELASTIC_APM_SERVICE_NAME=dotNetLoginService 32 | ENV ELASTIC_APM_ENVIRONMENT=production 33 | ENV PAL_OUTPUTDEBUGSTRING=1 34 | ENTRYPOINT ["dotnet", "login.dll"] -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/Dockerfile.elasticagent: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base 2 | WORKDIR /app 3 | EXPOSE 8000 4 | 5 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 6 | WORKDIR /src 7 | COPY ["login.csproj", "./"] 8 | RUN dotnet restore "./login.csproj" 9 | COPY . . 10 | WORKDIR "/src/." 11 | RUN dotnet build "login.csproj" -c Release -o /app/build 12 | 13 | FROM build AS publish 14 | RUN dotnet publish "login.csproj" -c Release -o /app/publish 15 | 16 | FROM base AS final 17 | WORKDIR /app 18 | COPY --from=publish /app/publish . 19 | 20 | ARG AGENT_VERSION=1.22.0 21 | 22 | RUN apt-get update && apt-get install -y zip curl 23 | RUN curl -L -o ElasticApmAgent_${AGENT_VERSION}.zip https://github.com/elastic/apm-agent-dotnet/releases/download/v${AGENT_VERSION}/ElasticApmAgent_${AGENT_VERSION}.zip && unzip ElasticApmAgent_${AGENT_VERSION}.zip -d /elastic_apm_agent 24 | 25 | ENV DOTNET_STARTUP_HOOKS=/elastic_apm_agent/ElasticApmAgentStartupHook.dll 26 | ENV ELASTIC_APM_SERVICE_NAME=dotNetLoginService 27 | ENV ELASTIC_APM_ENVIRONMENT=production 28 | 29 | ENTRYPOINT ["dotnet", "login.dll"] 30 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace UserService 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => 16 | { 17 | webBuilder.UseStartup(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:57723", 7 | "sslPort": 44388 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "UserService": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:8001;http://localhost:8000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | using Serilog; 7 | //using Serilog.Formatting.Compact; 8 | using Elastic.CommonSchema.Serilog; 9 | using Elastic.Apm.SerilogEnricher; 10 | 11 | namespace UserService 12 | { 13 | public class Startup 14 | { 15 | public Startup(IConfiguration configuration) 16 | { 17 | Configuration = configuration; 18 | } 19 | 20 | public IConfiguration Configuration { get; } 21 | 22 | public void ConfigureServices(IServiceCollection services) 23 | { 24 | services.AddControllers(); 25 | } 26 | 27 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 28 | { 29 | if (env.IsDevelopment()) 30 | { 31 | app.UseDeveloperExceptionPage(); 32 | } 33 | 34 | // app.UseHttpsRedirection(); 35 | 36 | Log.Logger = new LoggerConfiguration() 37 | .Enrich.WithElasticApmCorrelationInfo() 38 | .Enrich.WithProperty("metadata_event_dataset", "cartService.log") 39 | .WriteTo.Console(new EcsTextFormatter()).CreateLogger(); 40 | 41 | app.UseRouting(); 42 | 43 | app.UseAuthorization(); 44 | 45 | app.UseEndpoints(endpoints => 46 | { 47 | endpoints.MapControllers(); 48 | }); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/login.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-auto/login.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "login", "login.csproj", "{93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {FF212A10-C5E3-4511-8F39-AEB582271556} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-manual/Controllers/LoginController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Serilog; 5 | using Elastic.Apm; 6 | 7 | namespace login.Controllers 8 | { 9 | [ApiController] 10 | [Route("[controller]")] 11 | public class LoginController : ControllerBase 12 | { 13 | private static readonly List UserNames = new List 14 | { 15 | "Alice", 16 | "Bob", 17 | "Charlie", 18 | "Dave", 19 | "Eva" 20 | }; 21 | 22 | // Responds to GET requests. 23 | [HttpGet] 24 | public ActionResult Get() 25 | { 26 | 27 | var transaction = Elastic.Apm.Agent.Tracer.StartTransaction("MyTransaction","Request"); 28 | try 29 | { 30 | var user = GenerateRandomUserResponse(); 31 | Log.Information("User logged in: {UserName}", user); 32 | return user; 33 | } 34 | catch (Exception e) 35 | { 36 | transaction.CaptureException(e); 37 | throw; 38 | } 39 | finally 40 | { 41 | transaction.End(); 42 | } 43 | 44 | } 45 | 46 | // Responds to POST requests. 47 | [HttpPost] 48 | public ActionResult Post([FromBody] dynamic body) 49 | { 50 | var transaction = Elastic.Apm.Agent.Tracer.StartTransaction("MyTransaction", "Request"); 51 | try 52 | { 53 | var user = GenerateRandomUserResponse(); 54 | Log.Information("User logged in: {UserName}", user); 55 | return user; 56 | } 57 | catch (Exception e) 58 | { 59 | transaction.CaptureException(e); 60 | throw; 61 | } 62 | finally 63 | { 64 | transaction.End(); 65 | } 66 | } 67 | 68 | private ActionResult GenerateRandomUserResponse() 69 | { 70 | var random = new Random(); 71 | var index = random.Next(UserNames.Count); 72 | return Ok(new { userName = UserNames[index] }); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ${ARCH}mcr.microsoft.com/dotnet/aspnet:7.0. AS base 2 | WORKDIR /app 3 | EXPOSE 8000 4 | 5 | FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build 6 | WORKDIR /src 7 | COPY ["login.csproj", "./"] 8 | RUN dotnet restore "./login.csproj" 9 | COPY . . 10 | WORKDIR "/src/." 11 | RUN dotnet add package Elastic.Apm --version 1.22.0 12 | RUN dotnet build "login.csproj" -c Release -o /app/build 13 | 14 | FROM build AS publish 15 | RUN dotnet publish "login.csproj" -c Release -o /app/publish 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app/publish . 20 | 21 | ENV ELASTIC_APM_ENVIRONMENT=production 22 | ENV ELASTIC_APM_SECRET_TOKEN=XXX 23 | ENV ELASTIC_APM_SERVER_URL=https://2a773133cd7c4cf29134d0d4a81e3ae0.apm.us-central1.gcp.cloud.es.io:443 24 | ENV ELASTIC_APM_SERVICE_NAME=dotnet-login-elastic-auto 25 | 26 | ENTRYPOINT ["dotnet", "login.dll"] 27 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-manual/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace UserService 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => 16 | { 17 | webBuilder.UseStartup(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-manual/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:57723", 7 | "sslPort": 44388 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "UserService": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:8001;http://localhost:8000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-manual/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | using Serilog; 7 | //using Serilog.Formatting.Compact; 8 | using Elastic.CommonSchema.Serilog; 9 | using Elastic.Apm.SerilogEnricher; 10 | 11 | 12 | namespace UserService 13 | { 14 | public class Startup 15 | { 16 | public Startup(IConfiguration configuration) 17 | { 18 | Configuration = configuration; 19 | } 20 | 21 | public IConfiguration Configuration { get; } 22 | 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | services.AddControllers(); 26 | } 27 | 28 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 29 | { 30 | if (env.IsDevelopment()) 31 | { 32 | app.UseDeveloperExceptionPage(); 33 | } 34 | 35 | // app.UseHttpsRedirection(); 36 | 37 | Log.Logger = new LoggerConfiguration() 38 | .Enrich.WithElasticApmCorrelationInfo() 39 | .Enrich.WithProperty("metadata_event_dataset", "cartService.log") 40 | .WriteTo.Console(new EcsTextFormatter()).CreateLogger(); 41 | 42 | app.UseRouting(); 43 | 44 | app.UseAuthorization(); 45 | 46 | app.UseEndpoints(endpoints => 47 | { 48 | endpoints.MapControllers(); 49 | }); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-manual/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-manual/login.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-elastic-manual/login.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "login", "login.csproj", "{93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {FF212A10-C5E3-4511-8F39-AEB582271556} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-auto/Controllers/LoginController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Serilog; 5 | 6 | namespace login.Controllers 7 | { 8 | [ApiController] 9 | [Route("[controller]")] 10 | public class LoginController : ControllerBase 11 | { 12 | private static readonly List UserNames = new List 13 | { 14 | "Alice", 15 | "Bob", 16 | "Charlie", 17 | "Dave", 18 | "Eva" 19 | }; 20 | 21 | // Responds to GET requests. 22 | [HttpGet] 23 | public ActionResult Get() 24 | { 25 | var user = GenerateRandomUserResponse(); 26 | Log.Information("User logged in: {UserName}", user); 27 | return user; 28 | } 29 | 30 | // Responds to POST requests. 31 | [HttpPost] 32 | public ActionResult Post([FromBody] dynamic body) 33 | { 34 | // This is just an example, you might want to do something with the posted data. 35 | var user = GenerateRandomUserResponse(); 36 | Log.Information("User logged in: {UserName}", user); 37 | return user; 38 | } 39 | 40 | private ActionResult GenerateRandomUserResponse() 41 | { 42 | var random = new Random(); 43 | var index = random.Next(UserNames.Count); 44 | return Ok(new { userName = UserNames[index] }); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-auto/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ${ARCH}mcr.microsoft.com/dotnet/aspnet:7.0. AS base 2 | WORKDIR /app 3 | EXPOSE 8000 4 | 5 | FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build 6 | ARG TARGETPLATFORM 7 | 8 | WORKDIR /src 9 | COPY ["login.csproj", "./"] 10 | RUN dotnet restore "./login.csproj" 11 | COPY . . 12 | WORKDIR "/src/." 13 | RUN dotnet build "login.csproj" -c Release -o /app/build 14 | 15 | FROM build AS publish 16 | RUN dotnet publish "login.csproj" -c Release -o /app/publish 17 | 18 | FROM base AS final 19 | WORKDIR /app 20 | COPY --from=publish /app/publish . 21 | 22 | # Install dependencies 23 | RUN apt-get update && apt-get install -y zip curl 24 | RUN mkdir /otel 25 | RUN curl -L -o /otel/otel-dotnet-install.sh https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/download/v0.7.0/otel-dotnet-auto-install.sh 26 | RUN chmod +x /otel/otel-dotnet-install.sh 27 | 28 | #ENV OTEL_METRICS_EXPORTER=otlp 29 | #ENV OTEL_LOGS_EXPORTER=otlp 30 | #ENV OTEL_RESOURCE_ATTRIBUTES=service.name=dotNet,service.version=1.0,deployment.environment=production 31 | 32 | 33 | ENV OTEL_DOTNET_AUTO_HOME=/otel 34 | 35 | RUN /bin/bash /otel/otel-dotnet-install.sh 36 | 37 | # Provide necessary permissions for the script to execute 38 | RUN chmod +x /otel/instrument.sh 39 | 40 | COPY platform-detection.sh /otel/ 41 | 42 | # Run the platform detection script 43 | RUN chmod +x /otel/platform-detection.sh && /otel/platform-detection.sh 44 | 45 | # Run the env setup script and then start the dotnet application on container startup 46 | ENTRYPOINT ["/bin/bash", "-c", "source /otel/instrument.sh && dotnet login.dll"] 47 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-auto/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace UserService 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => 16 | { 17 | webBuilder.UseStartup(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-auto/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:57723", 7 | "sslPort": 44388 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "UserService": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:8001;http://localhost:8000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-auto/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | using Serilog; 7 | //using Serilog.Formatting.Compact; 8 | using Elastic.CommonSchema.Serilog; 9 | using Elastic.Apm.SerilogEnricher; 10 | 11 | namespace UserService 12 | { 13 | public class Startup 14 | { 15 | public Startup(IConfiguration configuration) 16 | { 17 | Configuration = configuration; 18 | } 19 | 20 | public IConfiguration Configuration { get; } 21 | 22 | public void ConfigureServices(IServiceCollection services) 23 | { 24 | services.AddControllers(); 25 | } 26 | 27 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 28 | { 29 | if (env.IsDevelopment()) 30 | { 31 | app.UseDeveloperExceptionPage(); 32 | } 33 | 34 | // app.UseHttpsRedirection(); 35 | 36 | Log.Logger = new LoggerConfiguration() 37 | .Enrich.WithElasticApmCorrelationInfo() 38 | .Enrich.WithProperty("metadata_event_dataset", "cartService.log") 39 | .WriteTo.Console(new EcsTextFormatter()).CreateLogger(); 40 | 41 | app.UseRouting(); 42 | 43 | app.UseAuthorization(); 44 | 45 | app.UseEndpoints(endpoints => 46 | { 47 | endpoints.MapControllers(); 48 | }); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-auto/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-auto/login.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-auto/login.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "login", "login.csproj", "{93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {FF212A10-C5E3-4511-8F39-AEB582271556} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-auto/platform-detection.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Detect the platform 4 | PLATFORM=$(uname -m) 5 | 6 | # Based on the platform, perform different operations 7 | if [ "$PLATFORM" = "aarch64" ]; then 8 | mv /otel/store/x64 /otel/store/arm64 9 | fi 10 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-manual/Controllers/LoginController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Serilog; 5 | using System.Diagnostics; 6 | using OpenTelemetry; 7 | using OpenTelemetry.Resources; 8 | using OpenTelemetry.Trace; 9 | using OpenTelemetry.Exporter; 10 | using OpenTelemetry; 11 | using OpenTelemetry.Exporter; 12 | using OpenTelemetry.Resources; 13 | using OpenTelemetry.Trace; 14 | 15 | namespace login.Controllers 16 | { 17 | 18 | [ApiController] 19 | [Route("[controller]")] 20 | public class LoginController : ControllerBase 21 | { 22 | 23 | 24 | private static readonly List UserNames = new List 25 | { 26 | "Alice", 27 | "Bob", 28 | "Charlie", 29 | "Dave", 30 | "Eva" 31 | }; 32 | 33 | // Responds to GET requests. 34 | [HttpGet] 35 | public ActionResult Get() 36 | { 37 | 38 | using (Activity activity = Telemetry.LoginActivitySource.StartActivity("SomeWork")) 39 | { 40 | var user = GenerateRandomUserResponse(); 41 | Log.Information("User logged in: {UserName}", user); 42 | return user; 43 | } 44 | 45 | 46 | 47 | } 48 | 49 | // Responds to POST requests. 50 | [HttpPost] 51 | public ActionResult Post([FromBody] dynamic body) 52 | { 53 | 54 | using (Activity activity = Telemetry.LoginActivitySource.StartActivity("SomeWork")) 55 | { 56 | var user = GenerateRandomUserResponse(); 57 | Log.Information("User logged in: {UserName}", user); 58 | return user; 59 | } 60 | } 61 | 62 | private ActionResult GenerateRandomUserResponse() 63 | { 64 | var random = new Random(); 65 | var index = random.Next(UserNames.Count); 66 | return Ok(new { userName = UserNames[index] }); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ${ARCH}mcr.microsoft.com/dotnet/aspnet:7.0. AS base 2 | WORKDIR /app 3 | EXPOSE 8000 4 | 5 | FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build 6 | WORKDIR /src 7 | COPY ["login.csproj", "./"] 8 | RUN dotnet restore "./login.csproj" 9 | COPY . . 10 | WORKDIR "/src/." 11 | 12 | RUN dotnet build "login.csproj" -c Release -o /app/build 13 | 14 | FROM build AS publish 15 | RUN dotnet publish "login.csproj" -c Release -o /app/publish 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app/publish . 20 | COPY appsettings.json . 21 | 22 | ENV OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 23 | ENV OTEL_TRACES_EXPORTER=otlp 24 | ENV OTEL_METRICS_EXPORTER=otlp 25 | ENV OTEL_LOGS_EXPORTER=otlp 26 | ENV OTEL_RESOURCE_ATTRIBUTES=service.name=Login,service.version=1.0.0,deployment.environment=production 27 | ENV OTEL_EXPORTER_OTLP_ENDPOINT=https://2a773133cd7c4cf29134d0d4a81e3ae0.apm.us-central1.gcp.cloud.es.io:443 28 | ENV OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer XXX" 29 | 30 | ENTRYPOINT ["dotnet", "login.dll"] 31 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-manual/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | using OpenTelemetry; 4 | using OpenTelemetry.Resources; 5 | using OpenTelemetry.Trace; 6 | using System; 7 | using System.Threading.Tasks; 8 | using OpenTelemetry.Exporter; 9 | using Microsoft.Extensions.Logging; 10 | using Serilog; 11 | 12 | namespace UserService 13 | { 14 | public class Program 15 | { 16 | public static void Main(string[] args) 17 | { 18 | Log.Logger = new LoggerConfiguration().WriteTo.Console().CreateLogger(); 19 | CreateHostBuilder(args).Build().Run(); 20 | } 21 | 22 | public static IHostBuilder CreateHostBuilder(string[] args) => 23 | Host.CreateDefaultBuilder(args) 24 | .ConfigureWebHostDefaults(webBuilder => 25 | { 26 | webBuilder.UseStartup(); 27 | }); 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-manual/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:57723", 7 | "sslPort": 44388 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "UserService": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:8001;http://localhost:8000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-manual/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | using Serilog; 7 | using OpenTelemetry; 8 | using OpenTelemetry.Resources; 9 | using OpenTelemetry.Trace; 10 | using Elastic.CommonSchema.Serilog; 11 | using Elastic.Apm.SerilogEnricher; 12 | using OpenTelemetry.Exporter; 13 | using System.Net.Http.Headers; 14 | 15 | 16 | // Define some important constants and the activity source. 17 | // These can come from a config file, constants file, etc. 18 | 19 | 20 | namespace UserService 21 | { 22 | public class Startup 23 | { 24 | public Startup(IConfiguration configuration) 25 | { 26 | Configuration = configuration; 27 | } 28 | 29 | public IConfiguration Configuration { get; } 30 | public void ConfigureServices(IServiceCollection services) 31 | { 32 | 33 | services.AddOpenTelemetry().WithTracing(builder => builder.AddOtlpExporter() 34 | .AddSource("Login") 35 | .AddAspNetCoreInstrumentation() 36 | .AddOtlpExporter() 37 | .ConfigureResource(resource => 38 | resource.AddService( 39 | serviceName: "Login")) 40 | ); 41 | 42 | services.AddControllers(); 43 | 44 | } 45 | 46 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 47 | { 48 | if (env.IsDevelopment()) 49 | { 50 | app.UseDeveloperExceptionPage(); 51 | } 52 | 53 | app.UseRouting(); 54 | 55 | app.UseAuthorization(); 56 | 57 | app.UseEndpoints(endpoints => 58 | { 59 | endpoints.MapControllers(); 60 | }); 61 | 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-manual/Telemetry.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | public static class Telemetry 4 | { 5 | //... 6 | 7 | // Name it after the service name for your app. 8 | // It can come from a config file, constants file, etc. 9 | public static readonly ActivitySource LoginActivitySource = new("Login"); 10 | 11 | //... 12 | } -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-manual/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "Microsoft": "Debug", 6 | "Microsoft.Hosting.Lifetime": "Debug" 7 | }, 8 | "Debug": { 9 | "LogLevel": { 10 | "Default": "Debug" 11 | } 12 | }, 13 | "Console": { 14 | "IncludeScopes": true, 15 | "LogLevel": { 16 | "Microsoft.Extensions.Hosting": "Debug", 17 | "Default": "Debug" 18 | } 19 | }, 20 | "EventSource": { 21 | "LogLevel": { 22 | "Microsoft": "Debug" 23 | } 24 | }, 25 | "EventLog": { 26 | "LogLevel": { 27 | "Microsoft": "Debug" 28 | } 29 | }, 30 | "AzureAppServicesFile": { 31 | "IncludeScopes": true, 32 | "LogLevel": { 33 | "Default": "Debug" 34 | } 35 | }, 36 | "AzureAppServicesBlob": { 37 | "IncludeScopes": true, 38 | "LogLevel": { 39 | "Microsoft": "Debug" 40 | } 41 | }, 42 | "ApplicationInsights": { 43 | "LogLevel": { 44 | "Default": "Debug" 45 | } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-manual/login.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login-otel-manual/login.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "login", "login.csproj", "{93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {FF212A10-C5E3-4511-8F39-AEB582271556} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login/Controllers/LoginController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Serilog; 5 | 6 | namespace login.Controllers 7 | { 8 | [ApiController] 9 | [Route("[controller]")] 10 | public class LoginController : ControllerBase 11 | { 12 | private static readonly List UserNames = new List 13 | { 14 | "Alice", 15 | "Bob", 16 | "Charlie", 17 | "Dave", 18 | "Eva" 19 | }; 20 | 21 | // Responds to GET requests. 22 | [HttpGet] 23 | public ActionResult Get() 24 | { 25 | var user = GenerateRandomUserResponse(); 26 | Log.Information("User logged in: {UserName}", user); 27 | return user; 28 | } 29 | 30 | // Responds to POST requests. 31 | [HttpPost] 32 | public ActionResult Post([FromBody] dynamic body) 33 | { 34 | // This is just an example, you might want to do something with the posted data. 35 | var user = GenerateRandomUserResponse(); 36 | Log.Information("User logged in: {UserName}", user); 37 | return user; 38 | } 39 | 40 | private ActionResult GenerateRandomUserResponse() 41 | { 42 | var random = new Random(); 43 | var index = random.Next(UserNames.Count); 44 | return Ok(new { userName = UserNames[index] }); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ${ARCH}mcr.microsoft.com/dotnet/aspnet:7.0. AS base 2 | WORKDIR /app 3 | EXPOSE 8000 4 | 5 | FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build 6 | WORKDIR /src 7 | COPY ["login.csproj", "./"] 8 | RUN dotnet restore "./login.csproj" 9 | COPY . . 10 | WORKDIR "/src/." 11 | RUN dotnet build "login.csproj" -c Release -o /app/build 12 | 13 | FROM build AS publish 14 | RUN dotnet publish "login.csproj" -c Release -o /app/publish 15 | 16 | FROM base AS final 17 | WORKDIR /app 18 | COPY --from=publish /app/publish . 19 | ENTRYPOINT ["dotnet", "login.dll"] -------------------------------------------------------------------------------- /Elastiflix/dotnet-login/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace UserService 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => 16 | { 17 | webBuilder.UseStartup(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:57723", 7 | "sslPort": 44388 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "UserService": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:8001;http://localhost:8000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | using Serilog; 7 | //using Serilog.Formatting.Compact; 8 | using Elastic.CommonSchema.Serilog; 9 | using Elastic.Apm.SerilogEnricher; 10 | 11 | namespace UserService 12 | { 13 | public class Startup 14 | { 15 | public Startup(IConfiguration configuration) 16 | { 17 | Configuration = configuration; 18 | } 19 | 20 | public IConfiguration Configuration { get; } 21 | 22 | public void ConfigureServices(IServiceCollection services) 23 | { 24 | services.AddControllers(); 25 | } 26 | 27 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 28 | { 29 | if (env.IsDevelopment()) 30 | { 31 | app.UseDeveloperExceptionPage(); 32 | } 33 | 34 | // app.UseHttpsRedirection(); 35 | 36 | Log.Logger = new LoggerConfiguration() 37 | .Enrich.WithElasticApmCorrelationInfo() 38 | .Enrich.WithProperty("metadata_event_dataset", "cartService.log") 39 | .WriteTo.Console(new EcsTextFormatter()).CreateLogger(); 40 | 41 | app.UseRouting(); 42 | 43 | app.UseAuthorization(); 44 | 45 | app.UseEndpoints(endpoints => 46 | { 47 | endpoints.MapControllers(); 48 | }); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login/login.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Elastiflix/dotnet-login/login.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "login", "login.csproj", "{93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {93E527AE-8BDA-4094-92BE-1ED5D29DEEE0}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {FF212A10-C5E3-4511-8F39-AEB582271556} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Elastiflix/go-favorite-elastic-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Golang image as the base image 2 | FROM golang:1.20-alpine AS build 3 | 4 | # Set the working directory to /app 5 | WORKDIR /app 6 | 7 | # Copy the source code to the container 8 | COPY . . 9 | 10 | # Build the application 11 | RUN go build -o /app/main 12 | 13 | # Use a minimal Alpine image as the base image for the final image 14 | FROM alpine:3.14 15 | 16 | # Copy the application binary from the build image to the final image 17 | COPY --from=build /app/main /app/main 18 | 19 | # Set the working directory to /app 20 | WORKDIR /app 21 | 22 | # Expose the port that the application listens on 23 | EXPOSE 5000 24 | 25 | # Start the application 26 | CMD ["/app/main"] -------------------------------------------------------------------------------- /Elastiflix/go-favorite-elastic-manual/go.mod: -------------------------------------------------------------------------------- 1 | module elastiflix/golang-favorite 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/gin-gonic/gin v1.9.1 7 | github.com/go-redis/redis/v8 v8.11.5 8 | github.com/sirupsen/logrus v1.9.3 9 | go.elastic.co/apm/module/apmgin/v2 v2.4.3 10 | go.elastic.co/apm/module/apmgoredisv8/v2 v2.4.3 11 | go.elastic.co/apm/module/apmlogrus/v2 v2.4.3 12 | ) 13 | 14 | require ( 15 | github.com/armon/go-radix v1.0.0 // indirect 16 | github.com/bytedance/sonic v1.9.1 // indirect 17 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 18 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 19 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 20 | github.com/elastic/go-sysinfo v1.11.0 // indirect 21 | github.com/elastic/go-windows v1.0.1 // indirect 22 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 23 | github.com/gin-contrib/sse v0.1.0 // indirect 24 | github.com/go-playground/locales v0.14.1 // indirect 25 | github.com/go-playground/universal-translator v0.18.1 // indirect 26 | github.com/go-playground/validator/v10 v10.14.0 // indirect 27 | github.com/goccy/go-json v0.10.2 // indirect 28 | github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect 29 | github.com/json-iterator/go v1.1.12 // indirect 30 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 31 | github.com/kr/pretty v0.1.0 // indirect 32 | github.com/leodido/go-urn v1.2.4 // indirect 33 | github.com/mattn/go-isatty v0.0.19 // indirect 34 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 35 | github.com/modern-go/reflect2 v1.0.2 // indirect 36 | github.com/pelletier/go-toml/v2 v2.0.8 // indirect 37 | github.com/pkg/errors v0.9.1 // indirect 38 | github.com/prometheus/procfs v0.11.0 // indirect 39 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 40 | github.com/ugorji/go/codec v1.2.11 // indirect 41 | go.elastic.co/apm/module/apmhttp/v2 v2.4.3 // indirect 42 | go.elastic.co/apm/v2 v2.4.3 // indirect 43 | go.elastic.co/fastjson v1.3.0 // indirect 44 | golang.org/x/arch v0.3.0 // indirect 45 | golang.org/x/crypto v0.9.0 // indirect 46 | golang.org/x/net v0.10.0 // indirect 47 | golang.org/x/sys v0.10.0 // indirect 48 | golang.org/x/text v0.9.0 // indirect 49 | google.golang.org/protobuf v1.30.0 // indirect 50 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 51 | gopkg.in/yaml.v3 v3.0.1 // indirect 52 | howett.net/plist v1.0.0 // indirect 53 | ) 54 | -------------------------------------------------------------------------------- /Elastiflix/go-favorite-otel-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Golang image as the base image 2 | FROM golang:1.20-alpine AS build 3 | 4 | # Set the working directory to /app 5 | WORKDIR /app 6 | 7 | # Copy the source code to the container 8 | COPY . . 9 | 10 | # Build the application 11 | RUN go build -o /app/main 12 | 13 | # Use a minimal Alpine image as the base image for the final image 14 | FROM alpine:3.14 15 | 16 | # Copy the application binary from the build image to the final image 17 | COPY --from=build /app/main /app/main 18 | 19 | # Set the working directory to /app 20 | WORKDIR /app 21 | 22 | # Expose the port that the application listens on 23 | EXPOSE 5000 24 | 25 | # Start the application 26 | CMD ["/app/main"] -------------------------------------------------------------------------------- /Elastiflix/go-favorite/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Golang image as the base image 2 | FROM golang:1.20-alpine AS build 3 | 4 | # Set the working directory to /app 5 | WORKDIR /app 6 | 7 | # Copy the source code to the container 8 | COPY . . 9 | 10 | # Build the application 11 | RUN go build -o /app/main 12 | 13 | # Use a minimal Alpine image as the base image for the final image 14 | FROM alpine:3.14 15 | 16 | # Copy the application binary from the build image to the final image 17 | COPY --from=build /app/main /app/main 18 | 19 | # Set the working directory to /app 20 | WORKDIR /app 21 | 22 | # Expose the port that the application listens on 23 | EXPOSE 5000 24 | 25 | # Start the application 26 | CMD ["/app/main"] -------------------------------------------------------------------------------- /Elastiflix/go-favorite/go.mod: -------------------------------------------------------------------------------- 1 | module elastiflix/golang-favorite 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/gin-gonic/gin v1.9.1 7 | github.com/go-redis/redis/v8 v8.11.5 8 | github.com/sirupsen/logrus v1.9.3 9 | ) 10 | 11 | require ( 12 | github.com/bytedance/sonic v1.9.1 // indirect 13 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 14 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 15 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 16 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 17 | github.com/gin-contrib/sse v0.1.0 // indirect 18 | github.com/go-playground/locales v0.14.1 // indirect 19 | github.com/go-playground/universal-translator v0.18.1 // indirect 20 | github.com/go-playground/validator/v10 v10.14.0 // indirect 21 | github.com/goccy/go-json v0.10.2 // indirect 22 | github.com/json-iterator/go v1.1.12 // indirect 23 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 24 | github.com/leodido/go-urn v1.2.4 // indirect 25 | github.com/mattn/go-isatty v0.0.19 // indirect 26 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 27 | github.com/modern-go/reflect2 v1.0.2 // indirect 28 | github.com/pelletier/go-toml/v2 v2.0.8 // indirect 29 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 30 | github.com/ugorji/go/codec v1.2.11 // indirect 31 | golang.org/x/arch v0.3.0 // indirect 32 | golang.org/x/crypto v0.9.0 // indirect 33 | golang.org/x/net v0.10.0 // indirect 34 | golang.org/x/sys v0.8.0 // indirect 35 | golang.org/x/text v0.9.0 // indirect 36 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 37 | google.golang.org/protobuf v1.30.0 // indirect 38 | gopkg.in/yaml.v3 v3.0.1 // indirect 39 | ) 40 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-auto/Dockerfile: -------------------------------------------------------------------------------- 1 | # Start with a base image containing Java runtime 2 | FROM maven:3.8.2-openjdk-17-slim as build 3 | 4 | # Make port 8080 available to the world outside this container 5 | EXPOSE 5000 6 | 7 | # Change to the app directory 8 | WORKDIR /usr/src/app 9 | 10 | # Copy the local code to the container 11 | COPY . . 12 | 13 | # Build the application 14 | RUN mvn clean install 15 | 16 | USER root 17 | RUN apt-get update && apt-get install -y zip curl 18 | 19 | ARG ELASTIC_AGENT_VERSION=1.46.0 20 | RUN mkdir /elastic_apm_agent 21 | RUN curl -L -o /elastic_apm_agent/elastic-apm-agent.jar https://repo1.maven.org/maven2/co/elastic/apm/elastic-apm-agent/${ELASTIC_AGENT_VERSION}/elastic-apm-agent-${ELASTIC_AGENT_VERSION}.jar 22 | 23 | COPY start.sh /start.sh 24 | RUN chmod +x /start.sh 25 | 26 | ENTRYPOINT ["/start.sh"] 27 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-auto/src/main/java/com/movieapi/FavoriteApplication.java: -------------------------------------------------------------------------------- 1 | package com.movieapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | @SpringBootApplication 12 | public class FavoriteApplication { 13 | private static final Logger logger = LoggerFactory.getLogger(FavoriteApplication.class); 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(FavoriteApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-auto/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | redis.host=localhost 2 | redis.port=6379 3 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-auto/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-auto/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | java \ 3 | -javaagent:/elastic_apm_agent/elastic-apm-agent.jar \ 4 | -Delastic.apm.application_packages=com.movieapi \ 5 | -jar /usr/src/app/target/favorite-0.0.1-SNAPSHOT.jar --server.port=5000 6 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | # Start with a base image containing Java runtime 2 | FROM maven:3.8.2-openjdk-17-slim as build 3 | 4 | # Make port 8080 available to the world outside this container 5 | EXPOSE 5000 6 | 7 | # Change to the app directory 8 | WORKDIR /usr/src/app 9 | 10 | # Copy the local code to the container 11 | COPY . . 12 | 13 | # Build the application 14 | RUN mvn clean install 15 | 16 | COPY start.sh /start.sh 17 | RUN chmod +x /start.sh 18 | 19 | ENTRYPOINT ["/start.sh"] 20 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-manual/src/main/java/com/movieapi/FavoriteApplication.java: -------------------------------------------------------------------------------- 1 | package com.movieapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | import co.elastic.apm.attach.ElasticApmAttacher; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | @SpringBootApplication 13 | public class FavoriteApplication { 14 | private static final Logger logger = LoggerFactory.getLogger(FavoriteApplication.class); 15 | 16 | public static void main(String[] args) { 17 | ElasticApmAttacher.attach(); 18 | 19 | SpringApplication.run(FavoriteApplication.class, args); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-manual/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | redis.host=localhost 2 | redis.port=6379 3 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-manual/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-elastic-manual/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | java -jar /usr/src/app/target/favorite-0.0.1-SNAPSHOT.jar --server.port=5000 3 | 4 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-auto/Dockerfile: -------------------------------------------------------------------------------- 1 | # Start with a base image containing Java runtime 2 | FROM maven:3.8.2-openjdk-17-slim as build 3 | 4 | # Make port 8080 available to the world outside this container 5 | EXPOSE 5000 6 | 7 | # Change to the app directory 8 | WORKDIR /usr/src/app 9 | 10 | # Copy the local code to the container 11 | COPY . . 12 | 13 | # Build the application 14 | RUN mvn clean install 15 | 16 | USER root 17 | RUN apt-get update && apt-get install -y zip curl 18 | 19 | ARG OTEL_AGENT_VERSION=2.0.0 20 | RUN mkdir /otel 21 | RUN curl -L -o /otel/opentelemetry-javaagent.jar https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v${OTEL_AGENT_VERSION}/opentelemetry-javaagent.jar 22 | 23 | # For now use only the latest snapshot 24 | RUN mkdir /elastic 25 | RUN curl -L -o /elastic/elastic-otel-javaagent.jar https://oss.sonatype.org/service/local/artifact/maven/redirect\?r\=snapshots\&g\=co.elastic.otel\&a\=elastic-otel-javaagent\&v\=LATEST 26 | 27 | COPY start.sh /start.sh 28 | RUN chmod +x /start.sh 29 | 30 | ENTRYPOINT ["/start.sh"] 31 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-auto/src/main/java/com/movieapi/FavoriteApplication.java: -------------------------------------------------------------------------------- 1 | package com.movieapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | @SpringBootApplication 12 | public class FavoriteApplication { 13 | private static final Logger logger = LoggerFactory.getLogger(FavoriteApplication.class); 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(FavoriteApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-auto/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | redis.host=localhost 2 | redis.port=6379 3 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-auto/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-auto/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | agent_path='' 4 | case "${AGENT_DISTRIBUTION:-otel}" in 5 | elastic) 6 | agent_path='/elastic/elastic-otel-javaagent.jar' 7 | ;; 8 | otel) 9 | agent_path='/otel/opentelemetry-javaagent.jar' 10 | ;; 11 | *) 12 | echo "unknown otel distribution: ${AGENT_DISTRIBUTION}" 13 | exit 1 14 | ;; 15 | esac 16 | 17 | folder="$(dirname $0)" 18 | 19 | java \ 20 | -javaagent:${agent_path} \ 21 | -jar /usr/src/app/target/favorite-0.0.1-SNAPSHOT.jar \ 22 | --server.port=5000 23 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | # Start with a base image containing Java runtime 2 | FROM maven:3.8.2-openjdk-17-slim as build 3 | 4 | # Make port 8080 available to the world outside this container 5 | EXPOSE 5000 6 | 7 | # Change to the app directory 8 | WORKDIR /usr/src/app 9 | 10 | # Copy the local code to the container 11 | COPY . . 12 | 13 | # Build the application 14 | RUN mvn clean install 15 | 16 | COPY start.sh /start.sh 17 | RUN chmod +x /start.sh 18 | 19 | ENTRYPOINT ["/start.sh"] 20 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-manual/src/main/java/com/movieapi/TracingFilter.java: -------------------------------------------------------------------------------- 1 | package com.movieapi; 2 | 3 | import io.opentelemetry.api.GlobalOpenTelemetry; 4 | import io.opentelemetry.api.trace.Span; 5 | import io.opentelemetry.api.trace.SpanKind; 6 | import io.opentelemetry.api.trace.StatusCode; 7 | import io.opentelemetry.api.trace.Tracer; 8 | import io.opentelemetry.context.Context; 9 | import io.opentelemetry.context.Scope; 10 | import io.opentelemetry.context.propagation.TextMapGetter; 11 | import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder; 12 | import jakarta.servlet.http.HttpServletRequest; 13 | import org.springframework.stereotype.Component; 14 | import org.springframework.web.filter.OncePerRequestFilter; 15 | 16 | 17 | import java.io.IOException; 18 | import java.util.Collections; 19 | 20 | @Component 21 | public class TracingFilter extends OncePerRequestFilter { 22 | String SERVICE_NAME = System.getenv("OTEL_SERVICE_NAME"); 23 | 24 | private static final TextMapGetter getter = 25 | new TextMapGetter() { 26 | @Override 27 | public Iterable keys(HttpServletRequest httpServletRequest) { 28 | return Collections.list(httpServletRequest.getHeaderNames()); 29 | } 30 | 31 | @Override 32 | public String get(HttpServletRequest httpServletRequest, String s) { 33 | return httpServletRequest.getHeader(s); 34 | } 35 | }; 36 | 37 | 38 | @Override 39 | protected void doFilterInternal(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response, jakarta.servlet.FilterChain filterChain) throws jakarta.servlet.ServletException, IOException { 40 | Tracer tracer = GlobalOpenTelemetry.getTracer(SERVICE_NAME); 41 | 42 | Context extractedContext = GlobalOpenTelemetry.getPropagators() 43 | .getTextMapPropagator() 44 | .extract(Context.current(), request, getter); 45 | 46 | Span span = tracer.spanBuilder(request.getRequestURI()) 47 | .setSpanKind(SpanKind.SERVER) 48 | .setParent(extractedContext) 49 | .startSpan(); 50 | 51 | try (Scope scope = span.makeCurrent()) { 52 | filterChain.doFilter(request, response); 53 | span.setStatus(StatusCode.OK); 54 | } catch (Exception e) { 55 | span.setStatus(StatusCode.ERROR); 56 | throw e; 57 | } finally { 58 | span.end(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-manual/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | redis.host=localhost 2 | redis.port=6379 3 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-manual/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | false 7 | true 8 | true 9 | 10 | 11 | 12 | 13 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite-otel-manual/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | java -jar /usr/src/app/target/favorite-0.0.1-SNAPSHOT.jar --server.port=5000 3 | 4 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite/Dockerfile: -------------------------------------------------------------------------------- 1 | # Start with a base image containing Java runtime 2 | FROM maven:3.8.2-openjdk-17-slim as build 3 | 4 | # Make port 8080 available to the world outside this container 5 | EXPOSE 5000 6 | 7 | # Change to the app directory 8 | WORKDIR /usr/src/app 9 | 10 | # Copy the local code to the container 11 | COPY . . 12 | 13 | # Build the application 14 | RUN mvn clean install 15 | 16 | COPY start.sh /start.sh 17 | RUN chmod +x /start.sh 18 | 19 | ENTRYPOINT ["/start.sh"] 20 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite/src/main/java/com/movieapi/FavoriteApplication.java: -------------------------------------------------------------------------------- 1 | package com.movieapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | @SpringBootApplication 12 | public class FavoriteApplication { 13 | private static final Logger logger = LoggerFactory.getLogger(FavoriteApplication.class); 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(FavoriteApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | redis.host=localhost 2 | redis.port=6379 3 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Elastiflix/java-favorite/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | java -jar /usr/src/app/target/favorite-0.0.1-SNAPSHOT.jar --server.port=5000 3 | 4 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/.env: -------------------------------------------------------------------------------- 1 | REACT_APP_ELASTIC_APM_SERVER_URL="https://foobar.apm.us-central1.gcp.cloud.es.io:443" 2 | REACT_APP_ELASTIC_APM_ENVIRONMENT="development" 3 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/.nvmrc: -------------------------------------------------------------------------------- 1 | v14.18.1 2 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 as build-deps 2 | WORKDIR /usr/src/app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn 5 | COPY ./ ./ 6 | RUN yarn build 7 | 8 | FROM nginx:1.25.1-alpine 9 | RUN apk --no-cache add curl 10 | COPY --from=build-deps /usr/src/app/build /usr/share/nginx/html 11 | COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf 12 | # Copy .env file and shell script to container 13 | WORKDIR /usr/share/nginx/html 14 | COPY --from=build-deps /usr/src/app/scripts ./ 15 | #COPY .env . 16 | RUN chmod +x ./*.sh 17 | # EXPOSE 8080 18 | # Add bash 19 | RUN apk add --no-cache bash 20 | # CMD ["/bin/bash", "-c", "/usr/share/nginx/html/retrieve-credentials.sh && nginx -g \"daemon off;\""] 21 | CMD [ "/bin/bash", "./docker-entrypoint.sh" ] 22 | # CMD ["nginx", "-g", "daemon off;"] 23 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 9000; 3 | server_name localhost; 4 | 5 | #charset koi8-r; 6 | #access_log /var/log/nginx/host.access.log main; 7 | root /usr/share/nginx/html; 8 | index index.html index.htm; 9 | location / { 10 | try_files $uri $uri/ /index.html?/$request_uri; 11 | } 12 | 13 | location /api { 14 | resolver 127.0.0.11; 15 | proxy_set_header X-Forwarded-Host $host; 16 | proxy_set_header X-Forwarded-Server $host; 17 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 18 | proxy_pass http://node-server:3001$request_uri; 19 | } 20 | location /search { 21 | resolver 127.0.0.11; 22 | proxy_set_header X-Forwarded-Host $host; 23 | proxy_set_header X-Forwarded-Server $host; 24 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 25 | proxy_pass http://node-server:3001$request_uri; 26 | } 27 | location /autocomplete { 28 | resolver 127.0.0.11; 29 | proxy_set_header X-Forwarded-Host $host; 30 | proxy_set_header X-Forwarded-Server $host; 31 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 32 | proxy_pass http://node-server:3001$request_uri; 33 | } 34 | 35 | #error_page 404 /404.html; 36 | 37 | # redirect server error pages to the static page /50x.html 38 | # 39 | error_page 500 502 503 504 /50x.html; 40 | location = /50x.html { 41 | root /usr/share/nginx/html; 42 | } 43 | 44 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80 45 | # 46 | #location ~ \.php$ { 47 | # proxy_pass http://127.0.0.1; 48 | #} 49 | 50 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 51 | # 52 | #location ~ \.php$ { 53 | # root html; 54 | # fastcgi_pass 127.0.0.1:9000; 55 | # fastcgi_index index.php; 56 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; 57 | # include fastcgi_params; 58 | #} 59 | 60 | # deny access to .htaccess files, if Apache's document root 61 | # concurs with nginx's one 62 | # 63 | #location ~ /\.ht { 64 | # deny all; 65 | #} 66 | } -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "streaming-ui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@elastic/apm-rum": "^5.12.0", 7 | "@elastic/apm-rum-react": "^1.4.2", 8 | "@elastic/datemath": "^5.0.3", 9 | "@elastic/eui": "^37.6.2", 10 | "@elastic/react-search-ui": "^1.7.0", 11 | "@elastic/search-ui-app-search-connector": "^1.20.2", 12 | "@elastic/search-ui-elasticsearch-connector": "^1.20.2", 13 | "@testing-library/jest-dom": "^5.11.4", 14 | "@testing-library/react": "^11.1.0", 15 | "@testing-library/user-event": "^12.1.10", 16 | "humanize-string": "^3.0.0", 17 | "moment": "^2.29.1", 18 | "prop-types": "^15.7.2", 19 | "react": "^16.12", 20 | "react-dom": "^16.12", 21 | "react-router-dom": "^5.3.0", 22 | "react-scripts": "4.0.3", 23 | "sass": "^1.39.0" 24 | }, 25 | "scripts": { 26 | "start": "react-scripts start", 27 | "build": "react-scripts build", 28 | "test": "react-scripts test", 29 | "eject": "react-scripts eject", 30 | "post-update": "yarn upgrade --latest" 31 | }, 32 | "eslintConfig": { 33 | "extends": [ 34 | "react-app", 35 | "react-app/jest" 36 | ] 37 | }, 38 | "browserslist": { 39 | "production": [ 40 | ">0.2%", 41 | "not dead", 42 | "not op_mini all" 43 | ], 44 | "development": [ 45 | "last 1 chrome version", 46 | "last 1 firefox version", 47 | "last 1 safari version" 48 | ] 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client-elastic-manual/public/favicon.ico -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/public/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Search and Stream 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client-elastic-manual/public/logo192.png -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client-elastic-manual/public/logo512.png -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/App.js: -------------------------------------------------------------------------------- 1 | import Routes from "./components/Routes"; 2 | import { BrowserRouter } from "react-router-dom"; 3 | import { init as initApm } from '@elastic/apm-rum' 4 | 5 | export const apm = initApm({ 6 | serviceName: process.env.NODE_ENV === 'development' ? "javascript-client-elastic-manual" : "${ELASTIC_APM_SERVICE_NAME}", 7 | //serverUrl: 'https://fef53b05d7d8455699151da2edc8f280.apm.us-central1.gcp.cloud.es.io:443', 8 | serverUrl: process.env.NODE_ENV === 'development' ? process.env.REACT_APP_ELASTIC_APM_SERVER_URL : "${ELASTIC_APM_SERVER_URL}", 9 | serviceVersion: '', 10 | environment: process.env.NODE_ENV === 'development' ? "dev" : "${ELASTIC_APM_ENVIRONMENT}", 11 | distributedTracingOrigins: ['http://localhost:3000','http://localhost:3001','http://localhost:9000'] 12 | }) 13 | 14 | function App() { 15 | return ( 16 | 17 | {/* */} 18 | 19 | 20 | ); 21 | } 22 | 23 | export default App; 24 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/coming-soon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client-elastic-manual/src/coming-soon.png -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/components/Card.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import ComingSoon from '../coming-soon.png' 3 | 4 | function Card(props) { 5 | const renderCast = !!props.movie.cast.raw.length &&

Starring {props.movie.cast.raw.slice(0, 4).map(c => c + ", ")} ...

6 | 7 | return ( 8 |
{ 11 | window.localStorage.setItem('movie', JSON.stringify({ 12 | title: props.movie.title.raw, 13 | description: props.movie.overview.raw, 14 | backdrop: `https://image.tmdb.org/t/p/original/${props.movie.poster_path.raw}`, 15 | id: props.movie.id.raw 16 | })) 17 | window.location.href = "/home" 18 | }} 19 | > 20 |
21 |
22 |
23 | 24 | {props.movie.title.raw} 25 |
26 |
27 |
28 |
29 |
30 |
31 |

32 |

33 | 34 | {Date(props.movie.release_date.raw) > new Date() ? 'Releasing ' : 'Released '} 35 | {new Intl.DateTimeFormat("en-GB", { 36 | year: "numeric", 37 | month: "long", 38 | day: "2-digit" 39 | }).format(new Date(props.movie.release_date.raw))} 40 |
41 |
42 |
43 |

44 |

45 | {renderCast} 46 |
47 |
48 |
49 | ) 50 | 51 | } 52 | 53 | export default Card 54 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/components/Home.js: -------------------------------------------------------------------------------- 1 | import Nav from "./Nav"; 2 | import Header from "./Header"; 3 | 4 | import Popular from "./Popular"; 5 | import Recent from "./Recent"; 6 | 7 | import { useState } from "react"; 8 | 9 | function Home() { 10 | const [movie, setMovie] = useState({ 11 | title: "Luca", 12 | description: "Luca and his best friend Alberto experience an unforgettable summer on the Italian Riviera. But all the fun is threatened by a deeply-held secret: they are sea monsters...", 13 | backdrop: "https://image.tmdb.org/t/p/original/jTswp6KyDYKtvC52GbHagrZbGvD.jpg", 14 | id: 508943 15 | }) 16 | 17 | return ( 18 |
19 |
26 | ) 27 | } 28 | 29 | export default Home 30 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TmdbLogo from '../tmdb-logo.svg'; 3 | 4 | const Layout = ({ children }) => 5 |
6 |
{children}
7 | 8 |
9 | Credits: This product uses the TMDB API but is not endorsed or certified by TMDB. 10 |
11 | 16 |
17 |
18 |
; 19 | 20 | 21 | export default Layout; 22 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/components/Nav.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import SearchBar from "./SearchBar"; 3 | import logo from '../logo.svg' 4 | 5 | function Nav(props) { 6 | 7 | // set to if testing locally with npm 8 | //const endpoint = ""; 9 | const endpoint = process.env.NODE_ENV === 'development' ? process.env.REACT_APP_NODE_BACKEND_HOST : "${NODE_BACKEND_HOST}" 10 | 11 | const [username, setUsername] = useState(""); 12 | const [isLoading, setIsLoading] = useState(true); 13 | const [error, setError] = useState(null); 14 | 15 | useEffect(() => { 16 | fetch(endpoint + '/api/login') // replace with your .NET service URL 17 | .then(response => { 18 | if (response.ok) { 19 | return response.json(); 20 | } else { 21 | throw new Error('Something went wrong ...'); 22 | } 23 | }) 24 | .then(data => { 25 | setUsername(data.userName); 26 | setIsLoading(false); 27 | }) 28 | .catch(error => { 29 | setIsLoading(false); 30 | setError(error); 31 | }); 32 | 33 | }, []); 34 | 35 | if (isLoading) { 36 | return
Loading ...
37 | } 38 | 39 | if (error) { 40 | return
Error: {error.message}
41 | } 42 | 43 | return ( 44 |
45 | 46 | 51 | 52 |
53 |
54 |
55 |

56 |
57 |
58 |
59 |
60 |
User: {username}
61 | {props.showSearch ?
62 | 63 |
: <>} 64 |
65 |
66 | ); 67 | } 68 | 69 | // Set default props 70 | Nav.defaultProps = { 71 | showSearch: false, 72 | fixed: false 73 | }; 74 | 75 | export default Nav; 76 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/components/Routes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, Switch, Redirect } from "react-router-dom"; 3 | import SearchPage from './SearchPage'; 4 | import Home from './Home.js'; 5 | import Layout from './Layout.js'; 6 | 7 | 8 | const Routes = () => ( 9 | <> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ) 19 | 20 | function RouteWrapper({ 21 | component: Component, 22 | layout: Layout, 23 | ...rest 24 | }) { 25 | return ( 26 | 27 | 28 | 29 | 30 | } /> 31 | ); 32 | } 33 | 34 | export default Routes; -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import "@elastic/react-search-ui-views/lib/styles/styles.css"; 4 | import '@elastic/eui/dist/eui_theme_light.css'; 5 | import './index.scss'; 6 | import App from './App'; 7 | 8 | 9 | ReactDOM.render( 10 | 11 | , 12 | document.getElementById('root') 13 | ); 14 | 15 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/src/tmdb-logo.svg: -------------------------------------------------------------------------------- 1 | Asset 3 -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/static/create-deployment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client-elastic-manual/static/create-deployment.gif -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/static/get-as-settings.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client-elastic-manual/static/get-as-settings.gif -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/static/get-cloud-id.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client-elastic-manual/static/get-cloud-id.gif -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/static/loader/get_as_base_url.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client-elastic-manual/static/loader/get_as_base_url.gif -------------------------------------------------------------------------------- /Elastiflix/javascript-client-elastic-manual/static/ui/ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client-elastic-manual/static/ui/ui.png -------------------------------------------------------------------------------- /Elastiflix/javascript-client/.env: -------------------------------------------------------------------------------- 1 | REACT_APP_NODE_BACKEND_HOST=http://localhost:3001 -------------------------------------------------------------------------------- /Elastiflix/javascript-client/.nvmrc: -------------------------------------------------------------------------------- 1 | v14.18.1 2 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 as build-deps 2 | WORKDIR /usr/src/app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn 5 | COPY ./ ./ 6 | RUN yarn build 7 | 8 | FROM nginx:1.25.1-alpine 9 | RUN apk --no-cache add curl 10 | COPY --from=build-deps /usr/src/app/build /usr/share/nginx/html 11 | COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf 12 | # Copy .env file and shell script to container 13 | WORKDIR /usr/share/nginx/html 14 | COPY --from=build-deps /usr/src/app/scripts ./ 15 | #COPY .env . 16 | RUN chmod +x ./*.sh 17 | # EXPOSE 8080 18 | # Add bash 19 | RUN apk add --no-cache bash 20 | # CMD ["/bin/bash", "-c", "/usr/share/nginx/html/retrieve-credentials.sh && nginx -g \"daemon off;\""] 21 | CMD [ "/bin/bash", "./docker-entrypoint.sh" ] 22 | # CMD ["nginx", "-g", "daemon off;"] 23 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 9000; 3 | server_name localhost; 4 | 5 | #charset koi8-r; 6 | #access_log /var/log/nginx/host.access.log main; 7 | root /usr/share/nginx/html; 8 | index index.html index.htm; 9 | location / { 10 | try_files $uri $uri/ /index.html?/$request_uri; 11 | } 12 | 13 | location /api { 14 | resolver 127.0.0.11; 15 | proxy_set_header X-Forwarded-Host $host; 16 | proxy_set_header X-Forwarded-Server $host; 17 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 18 | proxy_pass http://node-server:3001$request_uri; 19 | } 20 | location /search { 21 | resolver 127.0.0.11; 22 | proxy_set_header X-Forwarded-Host $host; 23 | proxy_set_header X-Forwarded-Server $host; 24 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 25 | proxy_pass http://node-server:3001$request_uri; 26 | } 27 | location /autocomplete { 28 | resolver 127.0.0.11; 29 | proxy_set_header X-Forwarded-Host $host; 30 | proxy_set_header X-Forwarded-Server $host; 31 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 32 | proxy_pass http://node-server:3001$request_uri; 33 | } 34 | 35 | #error_page 404 /404.html; 36 | 37 | # redirect server error pages to the static page /50x.html 38 | # 39 | error_page 500 502 503 504 /50x.html; 40 | location = /50x.html { 41 | root /usr/share/nginx/html; 42 | } 43 | 44 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80 45 | # 46 | #location ~ \.php$ { 47 | # proxy_pass http://127.0.0.1; 48 | #} 49 | 50 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 51 | # 52 | #location ~ \.php$ { 53 | # root html; 54 | # fastcgi_pass 127.0.0.1:9000; 55 | # fastcgi_index index.php; 56 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; 57 | # include fastcgi_params; 58 | #} 59 | 60 | # deny access to .htaccess files, if Apache's document root 61 | # concurs with nginx's one 62 | # 63 | #location ~ /\.ht { 64 | # deny all; 65 | #} 66 | } -------------------------------------------------------------------------------- /Elastiflix/javascript-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "streaming-ui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@elastic/datemath": "^5.0.3", 7 | "@elastic/eui": "^37.6.2", 8 | "@elastic/react-search-ui": "^1.7.0", 9 | "@elastic/search-ui-app-search-connector": "^1.20.2", 10 | "@elastic/search-ui-elasticsearch-connector": "^1.20.2", 11 | "@testing-library/jest-dom": "^5.11.4", 12 | "@testing-library/react": "^11.1.0", 13 | "@testing-library/user-event": "^12.1.10", 14 | "humanize-string": "^3.0.0", 15 | "moment": "^2.29.1", 16 | "prop-types": "^15.7.2", 17 | "react": "^16.12", 18 | "react-dom": "^16.12", 19 | "react-router-dom": "^5.3.0", 20 | "react-scripts": "4.0.3", 21 | "sass": "^1.39.0" 22 | }, 23 | "scripts": { 24 | "start": "react-scripts start", 25 | "build": "react-scripts build", 26 | "test": "react-scripts test", 27 | "eject": "react-scripts eject", 28 | "post-update": "yarn upgrade --latest" 29 | }, 30 | "eslintConfig": { 31 | "extends": [ 32 | "react-app", 33 | "react-app/jest" 34 | ] 35 | }, 36 | "browserslist": { 37 | "production": [ 38 | ">0.2%", 39 | "not dead", 40 | "not op_mini all" 41 | ], 42 | "development": [ 43 | "last 1 chrome version", 44 | "last 1 firefox version", 45 | "last 1 safari version" 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client/public/favicon.ico -------------------------------------------------------------------------------- /Elastiflix/javascript-client/public/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Search and Stream 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client/public/logo192.png -------------------------------------------------------------------------------- /Elastiflix/javascript-client/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client/public/logo512.png -------------------------------------------------------------------------------- /Elastiflix/javascript-client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/App.js: -------------------------------------------------------------------------------- 1 | import Routes from "./components/Routes"; 2 | import { BrowserRouter } from "react-router-dom"; 3 | 4 | function App() { 5 | return ( 6 | 7 | {/* */} 8 | 9 | 10 | ); 11 | } 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/coming-soon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client/src/coming-soon.png -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/components/Card.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import ComingSoon from '../coming-soon.png' 3 | 4 | function Card(props) { 5 | const renderCast = !!props.movie.cast.raw.length &&

Starring {props.movie.cast.raw.slice(0, 4).map(c => c + ", ")} ...

6 | 7 | return ( 8 |
{ 11 | window.localStorage.setItem('movie', JSON.stringify({ 12 | title: props.movie.title.raw, 13 | description: props.movie.overview.raw, 14 | backdrop: `https://image.tmdb.org/t/p/original/${props.movie.poster_path.raw}`, 15 | id: props.movie.id.raw 16 | })) 17 | window.location.href = "/home" 18 | }} 19 | > 20 |
21 |
22 |
23 | 24 | {props.movie.title.raw} 25 |
26 |
27 |
28 |
29 |
30 |
31 |

32 |

33 | 34 | {Date(props.movie.release_date.raw) > new Date() ? 'Releasing ' : 'Released '} 35 | {new Intl.DateTimeFormat("en-GB", { 36 | year: "numeric", 37 | month: "long", 38 | day: "2-digit" 39 | }).format(new Date(props.movie.release_date.raw))} 40 |
41 |
42 |
43 |

44 |

45 | {renderCast} 46 |
47 |
48 |
49 | ) 50 | 51 | } 52 | 53 | export default Card 54 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/components/Home.js: -------------------------------------------------------------------------------- 1 | import Nav from "./Nav"; 2 | import Header from "./Header"; 3 | 4 | import Popular from "./Popular"; 5 | import Recent from "./Recent"; 6 | 7 | import { useState } from "react"; 8 | 9 | function Home() { 10 | const [movie, setMovie] = useState({ 11 | title: "Luca", 12 | description: "Luca and his best friend Alberto experience an unforgettable summer on the Italian Riviera. But all the fun is threatened by a deeply-held secret: they are sea monsters...", 13 | backdrop: "https://image.tmdb.org/t/p/original/jTswp6KyDYKtvC52GbHagrZbGvD.jpg", 14 | id: 508943 15 | }) 16 | 17 | return ( 18 |
19 |
26 | ) 27 | } 28 | 29 | export default Home 30 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TmdbLogo from '../tmdb-logo.svg'; 3 | 4 | const Layout = ({ children }) => 5 |
6 |
{children}
7 | 8 |
9 | Credits: This product uses the TMDB API but is not endorsed or certified by TMDB. 10 |
11 | 16 |
17 |
18 |
; 19 | 20 | 21 | export default Layout; 22 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/components/Nav.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import SearchBar from "./SearchBar"; 3 | import logo from '../logo.svg' 4 | 5 | function Nav(props) { 6 | 7 | // set to if testing locally with npm 8 | //const endpoint = ""; 9 | const endpoint = process.env.NODE_ENV === 'development' ? process.env.REACT_APP_NODE_BACKEND_HOST : "${NODE_BACKEND_HOST}" 10 | 11 | const [username, setUsername] = useState(""); 12 | const [isLoading, setIsLoading] = useState(true); 13 | const [error, setError] = useState(null); 14 | 15 | useEffect(() => { 16 | fetch(endpoint + '/api/login') // replace with your .NET service URL 17 | .then(response => { 18 | if (response.ok) { 19 | return response.json(); 20 | } else { 21 | throw new Error('Something went wrong ...'); 22 | } 23 | }) 24 | .then(data => { 25 | setUsername(data.userName); 26 | setIsLoading(false); 27 | }) 28 | .catch(error => { 29 | setIsLoading(false); 30 | setError(error); 31 | }); 32 | 33 | }, []); 34 | 35 | if (isLoading) { 36 | return
Loading ...
37 | } 38 | 39 | if (error) { 40 | return
Error: {error.message}
41 | } 42 | 43 | return ( 44 |
45 | 46 | 51 | 52 |
53 |
54 |
55 |

56 |
57 |
58 |
59 |
60 |
User: {username}
61 | {props.showSearch ?
62 | 63 |
: <>} 64 |
65 |
66 | ); 67 | } 68 | 69 | // Set default props 70 | Nav.defaultProps = { 71 | showSearch: false, 72 | fixed: false 73 | }; 74 | 75 | export default Nav; 76 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/components/Routes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, Switch, Redirect } from "react-router-dom"; 3 | import SearchPage from './SearchPage'; 4 | import Home from './Home.js'; 5 | import Layout from './Layout.js'; 6 | 7 | 8 | const Routes = () => ( 9 | <> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ) 19 | 20 | function RouteWrapper({ 21 | component: Component, 22 | layout: Layout, 23 | ...rest 24 | }) { 25 | return ( 26 | 27 | 28 | 29 | 30 | } /> 31 | ); 32 | } 33 | 34 | export default Routes; -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import "@elastic/react-search-ui-views/lib/styles/styles.css"; 4 | import '@elastic/eui/dist/eui_theme_light.css'; 5 | import './index.scss'; 6 | import App from './App'; 7 | 8 | 9 | ReactDOM.render( 10 | 11 | , 12 | document.getElementById('root') 13 | ); 14 | 15 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /Elastiflix/javascript-client/src/tmdb-logo.svg: -------------------------------------------------------------------------------- 1 | Asset 3 -------------------------------------------------------------------------------- /Elastiflix/javascript-client/static/create-deployment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client/static/create-deployment.gif -------------------------------------------------------------------------------- /Elastiflix/javascript-client/static/get-as-settings.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client/static/get-as-settings.gif -------------------------------------------------------------------------------- /Elastiflix/javascript-client/static/get-cloud-id.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client/static/get-cloud-id.gif -------------------------------------------------------------------------------- /Elastiflix/javascript-client/static/loader/get_as_base_url.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client/static/loader/get_as_base_url.gif -------------------------------------------------------------------------------- /Elastiflix/javascript-client/static/ui/ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/javascript-client/static/ui/ui.png -------------------------------------------------------------------------------- /Elastiflix/locustfile.py: -------------------------------------------------------------------------------- 1 | from locust import HttpUser, task 2 | 3 | from time import sleep 4 | import random 5 | 6 | 7 | class HelloWorldUser(HttpUser): 8 | @task 9 | def hello_world(self): 10 | self.client.get("/api/favorites") 11 | 12 | if random.random() < 0.5: 13 | self.client.post("/api/favorites", json={"id": random.randint(1, 100)}) 14 | 15 | # in 50% of the cases, call the login endpoint 16 | if random.random() < 0.5: 17 | self.client.get("/api/login") 18 | sleep(1) 19 | -------------------------------------------------------------------------------- /Elastiflix/movie-data-loader/.nvmrc: -------------------------------------------------------------------------------- 1 | v14.18.1 2 | -------------------------------------------------------------------------------- /Elastiflix/movie-data-loader/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 2 | 3 | WORKDIR /app 4 | 5 | COPY ["package.json", "./"] 6 | RUN ls 7 | RUN npm install --production 8 | COPY . . 9 | 10 | CMD ["node", "index.js"] 11 | -------------------------------------------------------------------------------- /Elastiflix/movie-data-loader/movies.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/movie-data-loader/movies.json.gz -------------------------------------------------------------------------------- /Elastiflix/movie-data-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "movie-data-loader", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/elastic/Elastiflix.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/elastic/Elastiflix/issues" 19 | }, 20 | "homepage": "https://github.com/elastic/Elastiflix#readme", 21 | "dependencies": { 22 | "@elastic/elasticsearch": "^7.17.12" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Elastiflix/node-server-elastic-manual/.nvmrc: -------------------------------------------------------------------------------- 1 | v18.17.0 -------------------------------------------------------------------------------- /Elastiflix/node-server-elastic-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18.17.0 2 | 3 | WORKDIR /app 4 | 5 | COPY ["package.json", "./"] 6 | RUN ls 7 | RUN npm install --production 8 | COPY . . 9 | 10 | EXPOSE 3001 11 | 12 | CMD ["node", "index.js"] 13 | 14 | -------------------------------------------------------------------------------- /Elastiflix/node-server-elastic-manual/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elastiflix", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server/index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/elastic/Elastiflix.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/elastic/Elastiflix/issues" 19 | }, 20 | "homepage": "https://github.com/elastic/Elastiflix#readme", 21 | "dependencies": { 22 | "@elastic/ecs-morgan-format": "^1.1.0", 23 | "@elastic/ecs-pino-format": "^1.3.0", 24 | "@elastic/search-ui-elasticsearch-connector": "^1.20.2", 25 | "axios": "^1.4.0", 26 | "concurrently": "3.1.0", 27 | "cookie-parser": "^1.4.6", 28 | "cookieparser": "^0.1.0", 29 | "cors": "^2.8.5", 30 | "cross-fetch": "^4.0.0", 31 | "elastic-apm-node": "^3.48.0", 32 | "express": "^4.18.2", 33 | "express-http-proxy": "^1.6.3", 34 | "express-pino-logger": "^7.0.0", 35 | "morgan": "^1.10.0", 36 | "pino": "^8.14.2", 37 | "pino-http": "^8.3.3", 38 | "elastic-apm-node": "^3.48.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Elastiflix/node-server-otel-auto/.nvmrc: -------------------------------------------------------------------------------- 1 | v18.17.0 2 | -------------------------------------------------------------------------------- /Elastiflix/node-server-otel-auto/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18.17.0 2 | 3 | WORKDIR /app 4 | 5 | COPY ["package.json", "./"] 6 | RUN ls 7 | RUN npm install --production 8 | COPY . . 9 | 10 | RUN npm install --save @opentelemetry/api 11 | RUN npm install --save @opentelemetry/auto-instrumentations-node 12 | 13 | 14 | EXPOSE 3001 15 | 16 | CMD ["node", "--require", "@opentelemetry/auto-instrumentations-node/register", "index.js"] -------------------------------------------------------------------------------- /Elastiflix/node-server-otel-auto/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elastiflix", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server/index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/elastic/Elastiflix.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/elastic/Elastiflix/issues" 19 | }, 20 | "homepage": "https://github.com/elastic/Elastiflix#readme", 21 | "dependencies": { 22 | "@elastic/ecs-morgan-format": "^1.1.0", 23 | "@elastic/ecs-pino-format": "^1.3.0", 24 | "@elastic/search-ui-elasticsearch-connector": "^1.20.2", 25 | "axios": "^1.4.0", 26 | "concurrently": "3.1.0", 27 | "cookie-parser": "^1.4.6", 28 | "cookieparser": "^0.1.0", 29 | "cors": "^2.8.5", 30 | "cross-fetch": "^4.0.0", 31 | "elastic-apm-node": "^3.48.0", 32 | "express": "^4.18.2", 33 | "express-http-proxy": "^1.6.3", 34 | "express-pino-logger": "^7.0.0", 35 | "morgan": "^1.10.0", 36 | "pino": "^8.14.2", 37 | "pino-http": "^8.3.3" 38 | } 39 | } -------------------------------------------------------------------------------- /Elastiflix/node-server-otel-manual/.nvmrc: -------------------------------------------------------------------------------- 1 | v18.17.0 2 | -------------------------------------------------------------------------------- /Elastiflix/node-server-otel-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18.17.0 2 | 3 | WORKDIR /app 4 | 5 | COPY ["package.json", "./"] 6 | RUN ls 7 | RUN npm install --production 8 | COPY . . 9 | 10 | # the package.json contains these already so we don't have to 11 | # install them individually 12 | # RUN npm install --save @opentelemetry/api 13 | # RUN npm install --save @opentelemetry/resources 14 | # RUN npm install --save @opentelemetry/semantic-conventions 15 | # RUN npm install --save @opentelemetry/sdk-trace-node 16 | # RUN npm install --save @opentelemetry/sdk-trace-base 17 | # RUN npm install --save @opentelemetry/exporter-trace-otlp-grpc 18 | # RUN npm install --save @opentelemetry/instrumentation 19 | # RUN npm install --save @opentelemetry/instrumentation-http 20 | # RUN npm install --save @opentelemetry/instrumentation-express 21 | 22 | EXPOSE 3001 23 | 24 | CMD ["node", "index.js"] -------------------------------------------------------------------------------- /Elastiflix/node-server-otel-manual/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elastiflix", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server/index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/elastic/Elastiflix.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/elastic/Elastiflix/issues" 19 | }, 20 | "homepage": "https://github.com/elastic/Elastiflix#readme", 21 | "dependencies": { 22 | "@opentelemetry/api": "^1.4.1", 23 | "@opentelemetry/auto-instrumentations-node": "^0.38.0", 24 | "@opentelemetry/exporter-trace-otlp-grpc": "^0.41.0", 25 | "@opentelemetry/instrumentation": "^0.41.0", 26 | "@opentelemetry/instrumentation-express": "^0.33.0", 27 | "@opentelemetry/instrumentation-http": "^0.41.0", 28 | "@opentelemetry/resources": "^1.15.0", 29 | "@opentelemetry/sdk-node": "^0.41.0", 30 | "@opentelemetry/sdk-trace-base": "^1.15.0", 31 | "@opentelemetry/sdk-trace-node": "^1.15.0", 32 | "@opentelemetry/semantic-conventions": "^1.15.0", 33 | "@elastic/ecs-morgan-format": "^1.1.0", 34 | "@elastic/ecs-pino-format": "^1.3.0", 35 | "@elastic/search-ui-elasticsearch-connector": "^1.20.2", 36 | "axios": "^1.4.0", 37 | "concurrently": "3.1.0", 38 | "cookie-parser": "^1.4.6", 39 | "cookieparser": "^0.1.0", 40 | "cors": "^2.8.5", 41 | "cross-fetch": "^4.0.0", 42 | "express": "^4.18.2", 43 | "express-http-proxy": "^1.6.3", 44 | "express-pino-logger": "^7.0.0", 45 | "morgan": "^1.10.0", 46 | "pino": "^8.14.2", 47 | "pino-http": "^8.3.3" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Elastiflix/node-server/.nvmrc: -------------------------------------------------------------------------------- 1 | v18.17.0 2 | -------------------------------------------------------------------------------- /Elastiflix/node-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18.17.0 2 | 3 | WORKDIR /app 4 | 5 | COPY ["package.json", "./"] 6 | RUN ls 7 | RUN npm install --production 8 | COPY . . 9 | 10 | EXPOSE 3001 11 | 12 | CMD ["node", "index.js"] 13 | 14 | -------------------------------------------------------------------------------- /Elastiflix/node-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elastiflix", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server/index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/elastic/Elastiflix.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/elastic/Elastiflix/issues" 19 | }, 20 | "homepage": "https://github.com/elastic/Elastiflix#readme", 21 | "dependencies": { 22 | "@elastic/ecs-morgan-format": "^1.1.0", 23 | "@elastic/ecs-pino-format": "^1.3.0", 24 | "@elastic/search-ui-elasticsearch-connector": "^1.20.2", 25 | "axios": "^1.4.0", 26 | "concurrently": "3.1.0", 27 | "cookie-parser": "^1.4.6", 28 | "cookieparser": "^0.1.0", 29 | "cors": "^2.8.5", 30 | "cross-fetch": "^4.0.0", 31 | "elastic-apm-node": "^3.48.0", 32 | "express": "^4.18.2", 33 | "express-http-proxy": "^1.6.3", 34 | "express-pino-logger": "^7.0.0", 35 | "morgan": "^1.10.0", 36 | "pino": "^8.14.2", 37 | "pino-http": "^8.3.3" 38 | } 39 | } -------------------------------------------------------------------------------- /Elastiflix/otel-config-extras.yml: -------------------------------------------------------------------------------- 1 | # Copyright The OpenTelemetry Authors 2 | # SPDX-License-Identifier: Apache-2.0 3 | # extra settings to be merged into OpenTelemetry Collector configuration 4 | # do not delete this file 5 | exporters: 6 | otlp/elastic: 7 | # !!! Elastic APM https endpoint WITHOUT the "https://" prefix 8 | endpoint: "test-5a5402.apm.us-central1.gcp.cloud.es.io:443" 9 | headers: 10 | Authorization: "Bearer pkcQROVMCzYypqXs0b" 11 | 12 | processors: 13 | spanmetrics/elastic: 14 | metrics_exporter: otlp/elastic 15 | 16 | service: 17 | pipelines: 18 | traces: 19 | receivers: [otlp] 20 | processors: [spanmetrics/elastic, batch] 21 | exporters: [otlp/elastic] 22 | metrics: 23 | receivers: [otlp] 24 | processors: [filter, transform, batch] 25 | exporters: [otlp/elastic] 26 | logs: 27 | receivers: [otlp] 28 | processors: [batch] 29 | exporters: [otlp/elastic] -------------------------------------------------------------------------------- /Elastiflix/otel-config.yml: -------------------------------------------------------------------------------- 1 | # Copyright The OpenTelemetry Authors 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | receivers: 6 | otlp: 7 | protocols: 8 | grpc: 9 | http: 10 | cors: 11 | allowed_origins: 12 | - "http://*" 13 | - "https://*" 14 | 15 | exporters: 16 | otlp: 17 | endpoint: "jaeger:4317" 18 | tls: 19 | insecure: true 20 | logging: 21 | verbosity: detailed 22 | sampling_initial: 1 23 | sampling_thereafter: 1 24 | prometheus: 25 | endpoint: "otelcol:9464" 26 | resource_to_telemetry_conversion: 27 | enabled: true 28 | enable_open_metrics: true 29 | 30 | processors: 31 | batch: 32 | transform: 33 | metric_statements: 34 | - context: metric 35 | statements: 36 | - set(description, "Measures the duration of inbound HTTP requests") where name == "http.server.duration" 37 | filter: 38 | metrics: 39 | exclude: 40 | match_type: strict 41 | metric_names: 42 | - queueSize 43 | 44 | connectors: 45 | spanmetrics: 46 | 47 | service: 48 | pipelines: 49 | traces: 50 | receivers: [otlp] 51 | processors: [batch] 52 | exporters: [otlp, logging, spanmetrics] 53 | metrics: 54 | receivers: [otlp, spanmetrics] 55 | processors: [filter, transform, batch] 56 | exporters: [prometheus, logging] 57 | logs: 58 | receivers: [otlp] 59 | processors: [batch] 60 | exporters: [logging] -------------------------------------------------------------------------------- /Elastiflix/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "es_version": "8.9.0", 3 | "build_num": 10, 4 | "app_name": "elastiflix" 5 | } 6 | -------------------------------------------------------------------------------- /Elastiflix/python-favorite-elastic-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim as base 2 | 3 | # get packages 4 | COPY requirements.txt . 5 | RUN pip install -r requirements.txt 6 | WORKDIR /favoriteservice 7 | 8 | 9 | # Add the application 10 | COPY . . 11 | 12 | EXPOSE 5000 13 | ENTRYPOINT [ "python", "main.py" ] -------------------------------------------------------------------------------- /Elastiflix/python-favorite-elastic-manual/requirements.txt: -------------------------------------------------------------------------------- 1 | async-timeout==4.0.2 2 | blinker==1.6.2 3 | certifi==2023.5.7 4 | click==8.1.3 5 | ecs-logging==2.0.2 6 | elastic-apm==6.15.1 7 | Flask==2.3.2 8 | greenlet==2.0.2 9 | importlib-metadata==6.6.0 10 | itsdangerous==2.1.2 11 | Jinja2==3.1.2 12 | MarkupSafe==2.1.2 13 | marshmallow==3.19.0 14 | packaging==23.1 15 | psutil==5.9.5 16 | redis==4.5.5 17 | typing_extensions==4.6.2 18 | urllib3==2.0.2 19 | Werkzeug==2.3.4 20 | wrapt==1.15.0 21 | zipp==3.15.0 22 | -------------------------------------------------------------------------------- /Elastiflix/python-favorite-otel-auto/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim as base 2 | 3 | # get packages 4 | COPY requirements.txt . 5 | RUN pip install -r requirements.txt 6 | WORKDIR /favoriteservice 7 | 8 | #install opentelemetry packages 9 | RUN pip install opentelemetry-distro \ 10 | opentelemetry-exporter-otlp 11 | 12 | RUN opentelemetry-bootstrap -a install 13 | 14 | # Add the application 15 | COPY . . 16 | 17 | EXPOSE 5000 18 | ENTRYPOINT [ "opentelemetry-instrument", "python", "main.py"] -------------------------------------------------------------------------------- /Elastiflix/python-favorite-otel-auto/requirements.txt: -------------------------------------------------------------------------------- 1 | async-timeout==4.0.2 2 | blinker==1.6.2 3 | click==8.1.3 4 | ecs-logging==2.0.2 5 | Flask==2.3.2 6 | importlib-metadata==6.7.0 7 | itsdangerous==2.1.2 8 | Jinja2==3.1.2 9 | MarkupSafe==2.1.3 10 | redis==4.5.5 11 | Werkzeug==2.3.6 12 | zipp==3.15.0 13 | -------------------------------------------------------------------------------- /Elastiflix/python-favorite-otel-manual/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim as base 2 | 3 | ENV REDIS_HOST="redis" 4 | ENV REDIS_PORT="6379" 5 | ENV ENVIRONMENT="dev" 6 | ENV OTEL_SERVICE_NAME="favorite_otel_manual" 7 | ENV OTEL_SERVICE_VERSION="1.0.0" 8 | 9 | # get packages 10 | COPY requirements.txt . 11 | RUN pip install -r requirements.txt 12 | WORKDIR /favoriteservice 13 | 14 | 15 | # Add the application 16 | COPY . . 17 | 18 | EXPOSE 5000 19 | ENTRYPOINT [ "python", "main.py" ] -------------------------------------------------------------------------------- /Elastiflix/python-favorite-otel-manual/locustfile.py: -------------------------------------------------------------------------------- 1 | from locust import HttpUser, task 2 | 3 | from time import sleep 4 | import random 5 | 6 | 7 | class HelloWorldUser(HttpUser): 8 | @task 9 | def hello_world(self): 10 | self.client.get("/api/favorites") 11 | 12 | # in 50% of the cases, call the login endpoint 13 | if random.random() < 0.5: 14 | self.client.get("/api/login") 15 | sleep(100) 16 | -------------------------------------------------------------------------------- /Elastiflix/python-favorite-otel-manual/requirements.txt: -------------------------------------------------------------------------------- 1 | async-timeout==4.0.2 2 | blinker==1.6.2 3 | click==8.1.3 4 | ecs-logging==2.0.2 5 | Flask==2.3.2 6 | importlib-metadata~=6.0.0 7 | itsdangerous==2.1.2 8 | Jinja2==3.1.2 9 | MarkupSafe==2.1.3 10 | redis==4.5.5 11 | Werkzeug==2.3.6 12 | zipp==3.15.0 13 | opentelemetry-api==1.18.0 14 | opentelemetry-sdk==1.18.0 15 | opentelemetry-instrumentation==0.39b0 16 | opentelemetry-instrumentation-flask==0.39b0 17 | opentelemetry-instrumentation-requests==0.39b0 18 | opentelemetry-instrumentation-wsgi==0.39b0 19 | opentelemetry-instrumentation-redis==0.39b0 20 | opentelemetry-exporter-otlp==1.18.0 21 | -------------------------------------------------------------------------------- /Elastiflix/python-favorite/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim as base 2 | 3 | # get packages 4 | COPY requirements.txt . 5 | RUN pip install -r requirements.txt 6 | WORKDIR /favoriteservice 7 | 8 | 9 | # Add the application 10 | COPY . . 11 | 12 | EXPOSE 5000 13 | ENTRYPOINT [ "python", "main.py" ] -------------------------------------------------------------------------------- /Elastiflix/python-favorite/requirements.txt: -------------------------------------------------------------------------------- 1 | async-timeout==4.0.2 2 | blinker==1.6.2 3 | click==8.1.3 4 | ecs-logging==2.0.2 5 | Flask==2.3.2 6 | importlib-metadata==6.7.0 7 | itsdangerous==2.1.2 8 | Jinja2==3.1.2 9 | MarkupSafe==2.1.3 10 | redis==4.5.5 11 | Werkzeug==2.3.6 12 | zipp==3.15.0 13 | -------------------------------------------------------------------------------- /Elastiflix/redis/Dockerfile: -------------------------------------------------------------------------------- 1 | # dockerfile for redis with a background process to change the behavior of the redis server 2 | FROM redis:6.2.5-alpine 3 | 4 | 5 | COPY . . 6 | 7 | # use entrypoint.sh to run a background process to change the behavior of the redis server 8 | ENTRYPOINT ["sh", "./entrypoint.sh"] 9 | -------------------------------------------------------------------------------- /Elastiflix/redis/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # start a background process that periodially runs redis-cli CLIENT PAUSE to stall the server, if the env var TOGGLE_CLIENT_PAUSE is set to true 3 | echo "performing backup" >&1 4 | if [ "$TOGGLE_CLIENT_PAUSE" = "true" ]; then 5 | echo "Starting redis client-pause loop" 6 | while true; do 7 | echo "performing backup" >&1 8 | redis-cli CLIENT PAUSE 3000 >&1 9 | sleep 30 10 | done & 11 | fi 12 | 13 | # start redis 14 | echo "Starting redis-server" 15 | exec redis-server -------------------------------------------------------------------------------- /Elastiflix/screenshots/frontend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/screenshots/frontend.png -------------------------------------------------------------------------------- /Elastiflix/screenshots/inventory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/screenshots/inventory.png -------------------------------------------------------------------------------- /Elastiflix/screenshots/service-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/Elastiflix/screenshots/service-map.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash 2 | 3 | .PHONY: all 4 | all: lint 5 | 6 | .PHONY: lint 7 | lint: markdown-link-check pre-commit 8 | 9 | .PHONY: markdown-link-check 10 | markdown-link-check: 11 | docker run --rm \ 12 | --mount 'type=bind,source=$(PWD),target=/home/repo' \ 13 | --workdir /home/repo \ 14 | lycheeverse/lychee . 15 | 16 | .PHONY: pre-commit 17 | pre-commit: 18 | pre-commit run -a 19 | 20 | .PHONY: lint-fix 21 | lint-fix: 22 | ruff check --fix 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elastic Observability Examples 2 | 3 | This repository contains examples for Elastic Observability. 4 | 5 | Currently, it contains the following examples: 6 | - [Elastiflix](./Elastiflix/README.md) - a simple micro services movie app with different language implementations, showing both Elastic APM and OTel instrumentation 7 | - [Helloworld Demo App for Google Cloud Run](./gcp/run/README.md) - a hello world app for Google Cloud Run, instrumented with OTel 8 | -------------------------------------------------------------------------------- /anomaly-detection/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "transactions-generator", 3 | "version": "1.0.0", 4 | "description": "generate sample transactions", 5 | "main": "generate-transactions.js", 6 | "author": "Elastic NV", 7 | "license": "Apache-2.0", 8 | "devDependencies": { 9 | "@faker-js/faker": "^9.3.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /aws/app-runner/helloworld-observe/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim as base 2 | 3 | # get packages 4 | COPY requirements.txt . 5 | RUN pip install -r requirements.txt 6 | 7 | WORKDIR /app 8 | 9 | # install opentelemetry packages 10 | RUN pip install opentelemetry-distro opentelemetry-exporter-otlp 11 | RUN opentelemetry-bootstrap -a install 12 | 13 | ENV OTEL_EXPORTER_OTLP_ENDPOINT='' 14 | ENV OTEL_EXPORTER_OTLP_HEADERS='Authorization=Bearer%20' 15 | ENV OTEL_LOG_LEVEL=info 16 | ENV OTEL_METRICS_EXPORTER=otlp 17 | ENV OTEL_RESOURCE_ATTRIBUTES=service.version=1.0,deployment.environment=production 18 | ENV OTEL_SERVICE_NAME=helloworld 19 | ENV OTEL_TRACES_EXPORTER=otlp 20 | 21 | COPY . . 22 | ENV FLASK_APP=helloworld 23 | ENV FLASK_RUN_HOST=0.0.0.0 24 | ENV FLASK_RUN_PORT=8080 25 | EXPOSE 8080 26 | ENTRYPOINT [ "opentelemetry-instrument", "flask", "run" ] 27 | -------------------------------------------------------------------------------- /aws/app-runner/helloworld-observe/helloworld.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from flask import Flask 3 | 4 | from opentelemetry import trace 5 | 6 | tracer = trace.get_tracer("hello-world") 7 | 8 | app = Flask(__name__) 9 | 10 | 11 | @app.route("/") 12 | def helloworld(): 13 | with tracer.start_as_current_span("hi"): 14 | logging.info("hello") 15 | return """ 16 |
17 |

18 | Hello Elastic Observability - AWS App Runner - Python 19 |

20 | 21 |
22 | """ 23 | 24 | 25 | @app.after_request 26 | def after_request(response): 27 | with tracer.start_as_current_span("bye"): 28 | logging.info("goodbye") 29 | return response 30 | -------------------------------------------------------------------------------- /aws/app-runner/helloworld-observe/requirements.txt: -------------------------------------------------------------------------------- 1 | flask==2.3.3 2 | -------------------------------------------------------------------------------- /aws/app-runner/helloworld/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim as base 2 | 3 | # get packages 4 | COPY requirements.txt . 5 | RUN pip install -r requirements.txt 6 | 7 | WORKDIR /app 8 | 9 | COPY . . 10 | ENV FLASK_APP=helloworld 11 | ENV FLASK_RUN_HOST=0.0.0.0 12 | ENV FLASK_RUN_PORT=8080 13 | EXPOSE 8080 14 | ENTRYPOINT [ "flask", "run" ] 15 | -------------------------------------------------------------------------------- /aws/app-runner/helloworld/helloworld.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | 6 | @app.route("/") 7 | def helloworld(): 8 | return "

Hello World!

" 9 | -------------------------------------------------------------------------------- /aws/app-runner/helloworld/requirements.txt: -------------------------------------------------------------------------------- 1 | flask==2.3.3 2 | -------------------------------------------------------------------------------- /azure/container-apps/helloworld-observe/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ${ARCH}mcr.microsoft.com/dotnet/aspnet:7.0. AS base 2 | WORKDIR /app 3 | 4 | FROM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build 5 | ARG TARGETPLATFORM 6 | 7 | WORKDIR /src 8 | COPY ["helloworld.csproj", "./"] 9 | RUN dotnet restore "./helloworld.csproj" 10 | COPY . . 11 | WORKDIR "/src/." 12 | RUN dotnet build "helloworld.csproj" -c Release -o /app/build 13 | 14 | FROM build AS publish 15 | RUN dotnet publish "helloworld.csproj" -c Release -o /app/publish 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app/publish . 20 | EXPOSE 3500 21 | ENV ASPNETCORE_URLS=http://+:3500 22 | 23 | ENV OTEL_EXPORTER_OTLP_ENDPOINT='ELASTIC_APM_SERVER_URL' 24 | ENV OTEL_EXPORTER_OTLP_HEADERS='Authorization=Bearer ELASTIC_APM_SECRET_TOKEN' 25 | ENV OTEL_LOG_LEVEL=info 26 | ENV OTEL_METRICS_EXPORTER=otlp 27 | ENV OTEL_RESOURCE_ATTRIBUTES=service.version=1.0,deployment.environment=production 28 | ENV OTEL_SERVICE_NAME=helloworld 29 | ENV OTEL_TRACES_EXPORTER=otlp 30 | 31 | ENTRYPOINT ["dotnet", "helloworld.dll"] 32 | -------------------------------------------------------------------------------- /azure/container-apps/helloworld-observe/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using OpenTelemetry.Resources; 3 | using OpenTelemetry.Trace; 4 | 5 | var builder = WebApplication.CreateBuilder(args); 6 | builder.Services.AddOpenTelemetry().WithTracing(builder => builder.AddOtlpExporter() 7 | .AddSource("helloworld") 8 | .AddAspNetCoreInstrumentation() 9 | .AddOtlpExporter() 10 | .ConfigureResource(resource => 11 | resource.AddService( 12 | serviceName: "helloworld")) 13 | ); 14 | builder.Services.AddControllers(); 15 | var app = builder.Build(); 16 | 17 | string output = 18 | """ 19 |
20 |

21 | Hello Elastic Observability - Azure Container Apps - C# 22 |

23 | 24 |
25 | """; 26 | 27 | app.MapGet("/", async context => 28 | { 29 | using (Activity activity = Telemetry.activitySource.StartActivity("HelloSpan")!) 30 | { 31 | Console.Write("hello"); 32 | await context.Response.WriteAsync(output); 33 | } 34 | } 35 | ); 36 | app.Run(); 37 | -------------------------------------------------------------------------------- /azure/container-apps/helloworld-observe/Telemetry.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | public static class Telemetry 4 | { 5 | public static readonly ActivitySource activitySource = new("Helloworld"); 6 | } 7 | -------------------------------------------------------------------------------- /azure/container-apps/helloworld-observe/helloworld.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /azure/container-apps/helloworld/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ${ARCH}mcr.microsoft.com/dotnet/aspnet:7.0. AS base 2 | WORKDIR /app 3 | 4 | FROM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build 5 | WORKDIR /src 6 | COPY ["helloworld.csproj", "./"] 7 | RUN dotnet restore "./helloworld.csproj" 8 | COPY . . 9 | WORKDIR "/src/." 10 | RUN dotnet build "helloworld.csproj" -c Release -o /app/build 11 | 12 | FROM build AS publish 13 | RUN dotnet publish "helloworld.csproj" -c Release -o /app/publish 14 | 15 | FROM base AS final 16 | WORKDIR /app 17 | COPY --from=publish /app/publish . 18 | EXPOSE 3500 19 | ENV ASPNETCORE_URLS=http://+:3500 20 | 21 | ENTRYPOINT ["dotnet", "helloworld.dll"] 22 | -------------------------------------------------------------------------------- /azure/container-apps/helloworld/Program.cs: -------------------------------------------------------------------------------- 1 | var builder = WebApplication.CreateBuilder(args); 2 | var app = builder.Build(); 3 | 4 | string output = 5 | """ 6 |

Hello World!

7 | """; 8 | 9 | app.MapGet("/", async context => 10 | { await context.Response.WriteAsync(output); } 11 | ); 12 | app.Run(); 13 | -------------------------------------------------------------------------------- /azure/container-apps/helloworld/helloworld.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /chatbot-rag-app-observability/init-index-job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: init-elasticsearch-index-test 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: init-index 10 | #update your image location for chatbot rag app or continue to use this prebuilt one 11 | image: ghcr.io/elastic/elasticsearch-labs/chatbot-rag-app:latest 12 | workingDir: /app/api 13 | command: ["python3", "-m", "flask", "--app", "app", "create-index"] 14 | env: 15 | - name: FLASK_APP 16 | value: "app" 17 | - name: LLM_TYPE 18 | value: "openai" 19 | - name: CHAT_MODEL 20 | value: "gpt-4o-mini" 21 | - name: ES_INDEX 22 | value: "workplace-app-docs" 23 | - name: ES_INDEX_CHAT_HISTORY 24 | value: "workplace-app-docs-chat-history" 25 | - name: ELASTICSEARCH_URL 26 | valueFrom: 27 | secretKeyRef: 28 | name: chatbot-regular-secrets 29 | key: ELASTICSEARCH_URL 30 | - name: ELASTICSEARCH_USER 31 | valueFrom: 32 | secretKeyRef: 33 | name: chatbot-regular-secrets 34 | key: ELASTICSEARCH_USER 35 | - name: ELASTICSEARCH_PASSWORD 36 | valueFrom: 37 | secretKeyRef: 38 | name: chatbot-regular-secrets 39 | key: ELASTICSEARCH_PASSWORD 40 | envFrom: 41 | - secretRef: 42 | name: chatbot-regular-secrets 43 | restartPolicy: Never 44 | backoffLimit: 4 45 | -------------------------------------------------------------------------------- /chatbot-rag-app-observability/k8s-deployment-chatbot-rag-app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: chatbot-regular-secrets 5 | type: Opaque 6 | stringData: 7 | ELASTICSEARCH_URL: "YOUR_ELASTIC_SEARCH_URL" 8 | ELASTICSEARCH_USER: "elastic" 9 | ELASTICSEARCH_PASSWORD: "elastic" 10 | OTEL_EXPORTER_OTLP_HEADERS: "Authorization=Bearer%20xxxx" 11 | OTEL_EXPORTER_OTLP_ENDPOINT: "https://1234567.apm.us-west-2.aws.cloud.es.io:443" 12 | OPENAI_API_KEY: "YYYYYYYY" 13 | 14 | --- 15 | apiVersion: apps/v1 16 | kind: Deployment 17 | metadata: 18 | name: chatbot-regular 19 | spec: 20 | replicas: 2 21 | selector: 22 | matchLabels: 23 | app: chatbot-regular 24 | template: 25 | metadata: 26 | labels: 27 | app: chatbot-regular 28 | spec: 29 | containers: 30 | - name: chatbot-regular 31 | #Replace your image location below or continue to use this prebuilt version 32 | image: ghcr.io/elastic/elasticsearch-labs/chatbot-rag-app:latest 33 | ports: 34 | - containerPort: 4000 35 | env: 36 | - name: LLM_TYPE 37 | value: "openai" 38 | - name: CHAT_MODEL 39 | value: "gpt-4o-mini" 40 | - name: OTEL_RESOURCE_ATTRIBUTES 41 | value: "service.name=chatbot-regular,service.version=0.0.1,deployment.environment=dev" 42 | - name: OTEL_SDK_DISABLED 43 | value: "false" 44 | - name: OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT 45 | value: "true" 46 | - name: OTEL_EXPERIMENTAL_RESOURCE_DETECTORS 47 | value: "process_runtime,os,otel,telemetry_distro" 48 | - name: OTEL_EXPORTER_OTLP_PROTOCOL 49 | value: "http/protobuf" 50 | - name: OTEL_METRIC_EXPORT_INTERVAL 51 | value: "3000" 52 | - name: OTEL_BSP_SCHEDULE_DELAY 53 | value: "3000" 54 | envFrom: 55 | - secretRef: 56 | name: chatbot-regular-secrets 57 | resources: 58 | requests: 59 | memory: "512Mi" 60 | cpu: "250m" 61 | limits: 62 | memory: "1Gi" 63 | cpu: "500m" 64 | 65 | --- 66 | apiVersion: v1 67 | kind: Service 68 | metadata: 69 | name: chatbot-regular-service 70 | spec: 71 | selector: 72 | app: chatbot-regular 73 | ports: 74 | - port: 80 75 | targetPort: 4000 76 | type: LoadBalancer 77 | 78 | -------------------------------------------------------------------------------- /gcp/run/helloworld-observe/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-slim 2 | WORKDIR /usr/src/app 3 | COPY package*.json ./ 4 | RUN npm install --only=production 5 | COPY . ./ 6 | ENV OTEL_EXPORTER_OTLP_ENDPOINT='ELASTIC_APM_SERVER_URL' 7 | ENV OTEL_EXPORTER_OTLP_HEADERS='Authorization=Bearer ELASTIC_APM_SECRET_TOKEN' 8 | ENV OTEL_LOG_LEVEL=info 9 | ENV OTEL_METRICS_EXPORTER=otlp 10 | ENV OTEL_RESOURCE_ATTRIBUTES=service.version=1.0,deployment.environment=production 11 | ENV OTEL_SERVICE_NAME=helloworld 12 | ENV OTEL_TRACES_EXPORTER=otlp 13 | RUN npm install --save @opentelemetry/api 14 | RUN npm install --save @opentelemetry/auto-instrumentations-node 15 | CMD ["node", "--require", "@opentelemetry/auto-instrumentations-node/register", "index.js"] 16 | -------------------------------------------------------------------------------- /gcp/run/helloworld-observe/index.js: -------------------------------------------------------------------------------- 1 | const otel = require('@opentelemetry/api'); 2 | const tracer = otel.trace.getTracer('hello-world'); 3 | 4 | const express = require('express'); 5 | const app = express(); 6 | 7 | app.get('/', (req, res) => { 8 | tracer.startActiveSpan('hi', (span) => { 9 | console.log('hello'); 10 | span.end(); 11 | }); 12 | res.send( 13 | `
14 |

15 | Hello Elastic Observability - Google Cloud Run - Node.js 16 |

17 | 18 |
` 19 | ); 20 | tracer.startActiveSpan('bye', (span) => { 21 | console.log('goodbye'); 22 | span.end(); 23 | }); 24 | }); 25 | 26 | const port = parseInt(process.env.PORT) || 8080; 27 | app.listen(port, () => { 28 | console.log(`helloworld: listening on port ${port}`); 29 | }); 30 | -------------------------------------------------------------------------------- /gcp/run/helloworld-observe/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "helloworld", 3 | "description": "Hello World in Node.js with minimal instrumentation for Elastic Observability", 4 | "version": "1.0.0", 5 | "private": true, 6 | "main": "index.js", 7 | "scripts": { 8 | "start": "node index.js" 9 | }, 10 | "engines": { 11 | "node": ">= 12.0.0" 12 | }, 13 | "dependencies": { 14 | "express": "^4.18.2", 15 | "elastic-apm-node": "^3.49.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /gcp/run/helloworld/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-slim 2 | WORKDIR /usr/src/app 3 | COPY package*.json ./ 4 | RUN npm install --only=production 5 | COPY . ./ 6 | CMD [ "node", "index.js" ] 7 | -------------------------------------------------------------------------------- /gcp/run/helloworld/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | app.get('/', (req, res) => { 5 | res.send(`

Hello World!

`); 6 | }); 7 | 8 | const port = parseInt(process.env.PORT) || 8080; 9 | app.listen(port, () => { 10 | console.log(`helloworld: listening on port ${port}`); 11 | }); 12 | -------------------------------------------------------------------------------- /gcp/run/helloworld/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "helloworld", 3 | "description": "Hello World in Node.js", 4 | "version": "1.0.0", 5 | "private": true, 6 | "main": "index.js", 7 | "scripts": { 8 | "start": "node index.js" 9 | }, 10 | "engines": { 11 | "node": ">= 12.0.0" 12 | }, 13 | "dependencies": { 14 | "express": "^4.18.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /genai-function-calling/kibana-trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/genai-function-calling/kibana-trace.png -------------------------------------------------------------------------------- /genai-function-calling/openai-agents/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use glibc-based image with pre-compiled wheels for psutil 2 | FROM python:3.12-slim 3 | 4 | RUN --mount=type=cache,target=/root/.cache/pip python -m pip install --upgrade pip 5 | 6 | COPY requirements.txt /tmp 7 | RUN --mount=type=cache,target=/root/.cache/pip pip install -r /tmp/requirements.txt 8 | RUN --mount=type=cache,target=/root/.cache/pip edot-bootstrap --action=install 9 | 10 | COPY *.py / 11 | 12 | ENTRYPOINT [ "opentelemetry-instrument", "python", "main.py" ] 13 | -------------------------------------------------------------------------------- /genai-function-calling/openai-agents/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | genai-function-calling: 3 | container_name: genai-function-calling 4 | build: 5 | context: . 6 | env_file: 7 | - .env 8 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 9 | - "localhost:${HOST_IP:-host-gateway}" 10 | -------------------------------------------------------------------------------- /genai-function-calling/openai-agents/env.example: -------------------------------------------------------------------------------- 1 | # Update this with your real OpenAI API key 2 | OPENAI_API_KEY= 3 | 4 | # Uncomment to use Ollama instead of OpenAI 5 | # OPENAI_BASE_URL=http://localhost:11434/v1 6 | # OPENAI_API_KEY=unused 7 | # CHAT_MODEL=qwen3:0.6b 8 | 9 | # Uncomment to use RamaLama instead of OpenAI 10 | # OPENAI_BASE_URL=http://localhost:8080/v1 11 | # OPENAI_API_KEY=unused 12 | # CHAT_MODEL=qwen3:0.6b 13 | 14 | # Uncomment and complete if you want to use Azure OpenAI Service 15 | ## "Azure OpenAI Endpoint" in https://oai.azure.com/resource/overview 16 | # AZURE_OPENAI_ENDPOINT=https://YOUR_RESOURCE_NAME.openai.azure.com/ 17 | ## "API key 1 (or 2)" in https://oai.azure.com/resource/overview 18 | # AZURE_OPENAI_API_KEY= 19 | ## "Inference version" from https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation 20 | # OPENAI_API_VERSION=2024-10-01-preview 21 | ## "Name" from https://oai.azure.com/resource/deployments 22 | # CHAT_MODEL=YOUR_DEPLOYMENT_NAME 23 | 24 | OTEL_SERVICE_NAME=genai-function-calling 25 | 26 | # Default to send logs, traces and metrics to an OpenTelemetry collector, 27 | # accessible via localhost. For example, Elastic Distribution of OpenTelemetry 28 | # (EDOT) Collector. 29 | OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 30 | OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 31 | 32 | # Change to 'false' to hide prompt and completion content 33 | OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true 34 | 35 | # Export metrics every 3 seconds instead of every minute 36 | OTEL_METRIC_EXPORT_INTERVAL=3000 37 | # Export traces every 3 seconds instead of every 5 seconds 38 | OTEL_BSP_SCHEDULE_DELAY=3000 39 | # Change to affect behavior of which resources are detected. Note: these 40 | # choices are specific to the language, in this case Python. 41 | OTEL_EXPERIMENTAL_RESOURCE_DETECTORS=process_runtime,os,otel,telemetry_distro 42 | -------------------------------------------------------------------------------- /genai-function-calling/openai-agents/main_mcp.py: -------------------------------------------------------------------------------- 1 | import signal 2 | from typing import Callable, Awaitable 3 | 4 | from agents.mcp import MCPServerStdio, MCPUtil 5 | from mcp.server.fastmcp import FastMCP 6 | import os 7 | import sys 8 | 9 | from mcp.types import AnyFunction, Tool 10 | 11 | SERVER_ARG = "--mcp-server" 12 | 13 | 14 | def handler(signum, frame): 15 | sys.exit(0) 16 | 17 | 18 | async def server_main(fns: list[AnyFunction]): 19 | """Runs an MCP server which publishes the tool get_latest_elasticsearch_version.""" 20 | 21 | mcp_server = FastMCP(log_level="WARNING") 22 | for fn in fns: 23 | mcp_server.add_tool(fn) 24 | # Mysteriously, cleanup such as from opentelemetry-instrument does not run on exit 25 | # without registering an effectively no-op termination handler. 26 | signal.signal(signal.SIGTERM, handler) 27 | await mcp_server.run_stdio_async() 28 | 29 | 30 | async def client_main(tools_callback: Callable[[list[Tool]], Awaitable[None]]): 31 | """Starts an MCP server subprocess and invokes tools_callback with its tools.""" 32 | 33 | env = os.environ.copy() 34 | # Make sure PYTHONPATH is set to the same as what started this 35 | # process. Notably, opentelemetry-instrument removes itself from the value 36 | # in os.environ, and we'd like to restore it if it was used. 37 | env["PYTHONPATH"] = os.pathsep.join(sys.path) 38 | async with MCPServerStdio( 39 | { 40 | "command": sys.executable, 41 | "args": sys.argv + [SERVER_ARG], 42 | "env": env, 43 | } 44 | ) as server: 45 | tools = await server.list_tools() 46 | util = MCPUtil() 47 | tools = [util.to_function_tool(tool, server, False) for tool in tools] 48 | await tools_callback(tools) 49 | 50 | 51 | async def run_main(fns: list[AnyFunction], tools_callback: Callable[[list[Tool]], Awaitable[None]]): 52 | if SERVER_ARG in sys.argv: 53 | await server_main(fns) 54 | else: 55 | await client_main(tools_callback) 56 | -------------------------------------------------------------------------------- /genai-function-calling/openai-agents/main_test.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Elasticsearch B.V. and contributors 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | import pytest 6 | 7 | from main import main 8 | 9 | 10 | @pytest.mark.vcr 11 | @pytest.mark.asyncio 12 | async def test_main(default_openai_env, capsys): 13 | await main() 14 | 15 | reply = capsys.readouterr().out.strip() 16 | 17 | assert reply == "The latest version of Elasticsearch 8 is 8.18.0." 18 | -------------------------------------------------------------------------------- /genai-function-calling/openai-agents/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | asyncio_default_fixture_loop_scope = function 3 | -------------------------------------------------------------------------------- /genai-function-calling/openai-agents/requirements-dev.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | pytest-asyncio 3 | pytest-vcr 4 | -------------------------------------------------------------------------------- /genai-function-calling/openai-agents/requirements.txt: -------------------------------------------------------------------------------- 1 | openai-agents~=0.0.13 2 | httpx~=0.28.1 3 | mcp~=1.6.0 4 | 5 | elastic-opentelemetry~=1.0.0 6 | # Use openai-agents and MCP instrumentation from OpenInference 7 | openinference-instrumentation-openai-agents~=0.1.9 8 | openinference-instrumentation-mcp~=1.2.0 9 | -------------------------------------------------------------------------------- /genai-function-calling/semantic-kernel-dotnet/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | !Program.cs 4 | !*.csproj 5 | -------------------------------------------------------------------------------- /genai-function-calling/semantic-kernel-dotnet/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG DOTNET_VERSION=9.0 2 | 3 | FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-alpine AS edot 4 | ARG EDOT_VERSION=1.0.2 5 | ARG EDOT_INSTALL=https://github.com/elastic/elastic-otel-dotnet/releases/download/${EDOT_VERSION}/elastic-dotnet-auto-install.sh 6 | ENV OTEL_DOTNET_AUTO_HOME=/edot 7 | WORKDIR /edot 8 | RUN sh -c "$(curl -fsSL ${EDOT_INSTALL})" 9 | 10 | FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-alpine AS app 11 | WORKDIR /app 12 | COPY *.csproj ./ 13 | RUN dotnet restore 14 | COPY *.cs ./ 15 | RUN dotnet publish -c Release -p:AssemblyName=app -o out 16 | 17 | FROM mcr.microsoft.com/dotnet/runtime:${DOTNET_VERSION}-alpine 18 | 19 | # Copy EDOT from the build stage 20 | ENV OTEL_DOTNET_AUTO_HOME=/edot 21 | COPY --from=edot /edot /edot 22 | 23 | # Copy the application dll from the build stage 24 | WORKDIR /app 25 | COPY --from=app /app/out . 26 | 27 | ENTRYPOINT ["/edot/instrument.sh", "dotnet", "app.dll"] 28 | -------------------------------------------------------------------------------- /genai-function-calling/semantic-kernel-dotnet/README.md: -------------------------------------------------------------------------------- 1 | # Function Calling with Semantic Kernel .NET 2 | 3 | [Program.cs](Program.cs) implements the [example application flow][flow] using 4 | [Semantic Kernel][semantic-kernel] for .NET. 5 | 6 | [Dockerfile](Dockerfile) starts the application with Elastic Distribution 7 | of OpenTelemetry (EDOT) .NET, by prepending its command with `instrument.sh`. 8 | 9 | ## Configure 10 | 11 | Copy [env.example](env.example) to `.env` and update its `OPENAI_API_KEY`. 12 | 13 | An OTLP compatible endpoint should be listening for traces, metrics and logs on 14 | `http://localhost:4318`. If not, update `OTEL_EXPORTER_OTLP_ENDPOINT` as well. 15 | 16 | ## Run with Docker 17 | 18 | ```bash 19 | docker compose run --build --rm genai-function-calling 20 | ``` 21 | 22 | ## Run with Model Context Protocol (MCP) 23 | 24 | [Program.cs](Program.cs) includes code needed to decouple tool discovery and 25 | invocation via the [Model Context Protocol (MCP) flow][flow-mcp]. To run using 26 | MCP, append `-- --mcp` flag to your `docker compose run` command. 27 | 28 | ```bash 29 | docker compose run --build --rm genai-function-calling --mcp 30 | ``` 31 | 32 | ## Notes 33 | 34 | The LLM should generate something like "The latest stable version of 35 | Elasticsearch is 8.18.0", unless it hallucinates. Just run it again, if you 36 | see something else. 37 | 38 | Semantic Kernel .NET's OpenTelemetry instrumentation uses the following custom 39 | ENV variables, and only produces traces (not logs or metrics). 40 | ``` 41 | SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS=true 42 | SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS_SENSITIVE=true 43 | OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES="Microsoft.SemanticKernel*" 44 | ``` 45 | 46 | The official C# SDK for the Model Context Protocol also includes OpenTelemetry 47 | instrumentation, enabled when "Experimental.ModelContextProtocol*" is added to 48 | `OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES`. 49 | 50 | Finally, [Program.cs](Program.cs) is manually instrumented to start an activity 51 | in `Main`. This ensures various instrumentation file under a single trace and 52 | is enabled when "ElasticsearchVersionAgent" is added to 53 | `OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES`. 54 | 55 | --- 56 | [flow]: ../README.md#example-application-flow 57 | [semantic-kernel]: https://github.com/microsoft/semantic-kernel/tree/main/dotnet 58 | [flow-mcp]: ../README.md#model-context-protocol-flow 59 | -------------------------------------------------------------------------------- /genai-function-calling/semantic-kernel-dotnet/app.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /genai-function-calling/semantic-kernel-dotnet/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | genai-function-calling: 3 | container_name: genai-function-calling 4 | build: 5 | context: . 6 | env_file: 7 | - .env 8 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 9 | - "localhost:${HOST_IP:-host-gateway}" 10 | -------------------------------------------------------------------------------- /genai-function-calling/semantic-kernel-dotnet/env.example: -------------------------------------------------------------------------------- 1 | # Update this with your real OpenAI API key 2 | OPENAI_API_KEY= 3 | 4 | # Uncomment to use Ollama instead of OpenAI 5 | # OPENAI_BASE_URL=http://localhost:11434/v1 6 | # OPENAI_API_KEY=unused 7 | # CHAT_MODEL=qwen3:0.6b 8 | 9 | # Uncomment to use RamaLama instead of OpenAI 10 | # OPENAI_BASE_URL=http://localhost:8080/v1 11 | # OPENAI_API_KEY=unused 12 | # CHAT_MODEL=qwen3:0.6b 13 | 14 | # Uncomment and complete if you want to use Azure OpenAI Service 15 | ## "Azure OpenAI Endpoint" in https://oai.azure.com/resource/overview 16 | # AZURE_OPENAI_ENDPOINT=https://YOUR_RESOURCE_NAME.openai.azure.com/ 17 | ## "API key 1 (or 2)" in https://oai.azure.com/resource/overview 18 | # AZURE_OPENAI_API_KEY= 19 | ## "Inference version" from https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation 20 | # OPENAI_API_VERSION=2024-10-01-preview 21 | ## "Name" from https://oai.azure.com/resource/deployments 22 | # CHAT_MODEL=YOUR_DEPLOYMENT_NAME 23 | 24 | # OpenTelemetry configuration for SemanticKernel 25 | SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS=true 26 | SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS_SENSITIVE=true 27 | OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES="ElasticsearchVersionAgent,Microsoft.SemanticKernel*,Experimental.ModelContextProtocol*" 28 | 29 | # Default to send logs, traces and metrics to an OpenTelemetry collector, 30 | # accessible via localhost. For example, Elastic Distribution of OpenTelemetry 31 | # (EDOT) Collector. 32 | OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 33 | OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 34 | 35 | OTEL_SERVICE_NAME=genai-function-calling 36 | -------------------------------------------------------------------------------- /genai-function-calling/spring-ai/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip 20 | -------------------------------------------------------------------------------- /genai-function-calling/spring-ai/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:21-jdk-alpine AS build 2 | 3 | WORKDIR /build 4 | 5 | # Install dependencies (verify resolves more than dependency:go-offline) 6 | COPY mvnw ./ 7 | COPY .mvn ./.mvn 8 | COPY pom.xml ./ 9 | RUN ./mvnw verify -DskipTests 10 | 11 | # Copy source code and build the application 12 | COPY src ./src 13 | RUN ./mvnw package 14 | 15 | FROM eclipse-temurin:21-jre-alpine 16 | 17 | COPY --from=build /build/target/genai-function-calling-*.jar /genai-function-calling.jar 18 | COPY --from=build /build/target/elastic-otel-javaagent.jar /elastic-otel-javaagent.jar 19 | 20 | ENTRYPOINT ["java", "-javaagent:/elastic-otel-javaagent.jar", "-cp", "./genai-function-calling.jar", "org.springframework.boot.loader.launch.PropertiesLauncher"] 21 | -------------------------------------------------------------------------------- /genai-function-calling/spring-ai/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | genai-function-calling: 3 | container_name: genai-function-calling 4 | build: 5 | context: ./ 6 | env_file: 7 | - .env 8 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 9 | - "localhost:${HOST_IP:-host-gateway}" 10 | -------------------------------------------------------------------------------- /genai-function-calling/spring-ai/env.example: -------------------------------------------------------------------------------- 1 | # Update this with your real OpenAI API key 2 | OPENAI_API_KEY= 3 | 4 | # Uncomment to use Ollama instead of OpenAI 5 | # OPENAI_BASE_URL=http://localhost:11434/v1 6 | # OPENAI_API_KEY=unused 7 | # # This works when you supply a major_version parameter in your prompt. If you 8 | # # leave it out, you need to update this to qwen3:1.7b to proceed the tool call. 9 | # CHAT_MODEL=qwen3:0.6b 10 | 11 | # Uncomment to use RamaLama instead of OpenAI 12 | # OPENAI_BASE_URL=http://localhost:8080/v1 13 | # OPENAI_API_KEY=unused 14 | # # This works when you supply a major_version parameter in your prompt. If you 15 | # # leave it out, you need to update this to qwen3:1.7b to proceed the tool call. 16 | # CHAT_MODEL=qwen3:0.6b 17 | 18 | # Uncomment and complete if you want to use Azure OpenAI Service 19 | ## "Azure OpenAI Endpoint" in https://oai.azure.com/resource/overview 20 | # AZURE_OPENAI_ENDPOINT=https://YOUR_RESOURCE_NAME.openai.azure.com/ 21 | ## "API key 1 (or 2)" in https://oai.azure.com/resource/overview 22 | # AZURE_OPENAI_API_KEY= 23 | ## "Inference version" from https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation 24 | # OPENAI_API_VERSION=2024-10-01-preview 25 | ## "Name" from https://oai.azure.com/resource/deployments 26 | # CHAT_MODEL=YOUR_DEPLOYMENT_NAME 27 | 28 | # OpenTelemetry configuration for Spring AI 29 | # Disable spring-boot built-in HTTP instrumentation because it does not follow OTel conventions and ends up as a sibling 30 | # of javaagent's instrumentation. Also exclude Azure OpenAI which cannot be active at the same time as OpenAI until 31 | # https://github.com/spring-projects/spring-ai/issues/2392 32 | SPRING_AUTOCONFIGURE_EXCLUDE=org.springframework.boot.actuate.autoconfigure.observation.web.client.HttpClientObservationsAutoConfiguration,org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiAutoConfiguration 33 | # Disable OpenAI which cannot be active at the same time as Azure OpenAI until 34 | # https://github.com/spring-projects/spring-ai/issues/2392 35 | # SPRING_AUTOCONFIGURE_EXCLUDE=org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration 36 | OTEL_INSTRUMENTATION_MICROMETER_ENABLED=true 37 | 38 | # Default to send logs, traces and metrics to an OpenTelemetry collector, 39 | # accessible via localhost. For example, Elastic Distribution of OpenTelemetry 40 | # (EDOT) Collector. 41 | OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 42 | OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 43 | 44 | OTEL_SERVICE_NAME=genai-function-calling 45 | -------------------------------------------------------------------------------- /genai-function-calling/spring-ai/src/main/java/example/ElasticsearchTools.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import jakarta.annotation.Nullable; 4 | import org.springframework.ai.tool.annotation.Tool; 5 | import org.springframework.ai.tool.annotation.ToolParam; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.reactive.function.client.WebClient; 9 | 10 | import java.util.Comparator; 11 | import java.util.List; 12 | 13 | 14 | @Component 15 | class ElasticsearchTools { 16 | record Release(String version, String public_release_date) { 17 | } 18 | 19 | record ReleasesResponse(List releases) { 20 | } 21 | 22 | @Tool(description = "Returns the latest GA version of Elasticsearch in \"X.Y.Z\" format.") 23 | String getLatestElasticsearchVersion(@ToolParam(description = "Major version to filter by (e.g. 7, 8). Defaults to latest") @Nullable Integer majorVersion) { 24 | ReleasesResponse response = WebClient.create().get().uri("https://artifacts.elastic.co/releases/stack.json") 25 | .exchangeToMono(res -> res.mutate() 26 | // Fix incorrect content-type from artifacts.elastic.co 27 | .headers(hdrs -> hdrs.setContentType(MediaType.APPLICATION_JSON)) 28 | .build() 29 | .bodyToMono(ReleasesResponse.class)) 30 | .block(); 31 | return response.releases().stream() 32 | // Filter out non-release versions (e.g. -rc1) and remove " GA" suffix 33 | .map(release -> release.version().replace(" GA", "")) 34 | .filter(version -> !version.contains("-")) 35 | .filter(version -> { 36 | if (majorVersion == null) { 37 | return true; 38 | } 39 | return version.startsWith(majorVersion + "."); 40 | }) 41 | // "8.9.1" > "8.10.0", so coerce to an integer: 80901 < 81000 42 | .max(Comparator.comparingInt(v -> { 43 | String[] parts = v.split("\\."); 44 | return Integer.parseInt(parts[0]) * 10000 + 45 | Integer.parseInt(parts[1]) * 100 + 46 | Integer.parseInt(parts[2]); 47 | })) 48 | .orElseThrow(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /genai-function-calling/spring-ai/src/main/java/example/VersionAgent.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import io.micrometer.tracing.annotation.NewSpan; 4 | import org.springframework.ai.chat.client.ChatClient; 5 | import org.springframework.ai.chat.model.ChatModel; 6 | import org.springframework.ai.model.tool.DefaultToolCallingChatOptions; 7 | import org.springframework.ai.tool.ToolCallbackProvider; 8 | import org.springframework.boot.CommandLineRunner; 9 | import org.springframework.context.ConfigurableApplicationContext; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | class VersionAgent implements CommandLineRunner { 14 | 15 | private final ChatClient chat; 16 | private final ToolCallbackProvider tools; 17 | private final ConfigurableApplicationContext context; 18 | 19 | VersionAgent(ChatModel chat, ToolCallbackProvider tools, ConfigurableApplicationContext context) { 20 | this.chat = ChatClient.builder(chat).build(); 21 | this.tools = tools; 22 | this.context = context; 23 | } 24 | 25 | @Override 26 | // Without a root span, we get multiple traces and can't understand the multiple requests being made. 27 | // Currently, no automatic root span is created for the CommandLineRunner so we do it ourselves. 28 | // https://github.com/spring-projects/spring-ai/issues/1440 29 | @NewSpan("version-agent") 30 | public void run(String... args) { 31 | String answer = chat.prompt() 32 | .user("What is the latest version of Elasticsearch 8?") 33 | .toolCallbacks(tools) 34 | .options(DefaultToolCallingChatOptions.builder().temperature(0.0).build()) 35 | .call() 36 | .content(); 37 | 38 | System.out.println(answer); 39 | context.close(); // See https://github.com/spring-projects/spring-ai/issues/2756 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /genai-function-calling/spring-ai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | # See https://docs.spring.io/spring-ai/reference/api/chat/openai-chat.html 2 | spring: 3 | main: 4 | web-application-type: none 5 | banner-mode: "off" 6 | ai: 7 | model: 8 | # Disable all models by default and enable per example to avoid eager autoconfiguration. 9 | # https://github.com/spring-projects/spring-ai/blob/main/spring-ai-model/src/main/java/org/springframework/ai/model/SpringAIModelProperties.java#L37 10 | embedding: none 11 | embedding.text: none 12 | embedding.multimodal: none 13 | image: none 14 | audio.transcription: none 15 | audio.speech: none 16 | moderation: none 17 | openai: 18 | base-url: ${OPENAI_BASE_URL:https://api.openai.com/v1} 19 | api-key: ${OPENAI_API_KEY:enter-your-api-key} 20 | chat: 21 | options: 22 | model: ${CHAT_MODEL:gpt-4o-mini} 23 | # ensure /v1 isn't appended twice 24 | completions-path: /chat/completions 25 | azure.openai: 26 | api-key: ${AZURE_OPENAI_API_KEY:} 27 | endpoint: ${AZURE_OPENAI_ENDPOINT:} 28 | chat: 29 | options: 30 | deployment-name: ${CHAT_MODEL:} 31 | 32 | chat: 33 | observations: 34 | log-prompt: true 35 | log-completion: true 36 | include-error-logging: true 37 | 38 | management.observations.annotations.enabled: true 39 | 40 | logging: 41 | level: 42 | root: WARN 43 | 44 | io: 45 | netty: 46 | resolver: 47 | dns: 48 | # Hush warnings about native DNS on MacOS 49 | DnsServerAddressStreamProviders: OFF 50 | org: 51 | springframework: 52 | # Note: Prompt and completion logging is via SLF4J, which cannot set 53 | # the OpenTelemetry log attribute "event.name". 54 | ai: 55 | chat: 56 | observation: INFO 57 | client: 58 | observation: INFO 59 | model: 60 | chat: 61 | observation: 62 | autoconfigure: 63 | # Hush warnings about prompt and completion logging 64 | ChatObservationAutoConfiguration: OFF 65 | -------------------------------------------------------------------------------- /genai-function-calling/vercel-ai/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /genai-function-calling/vercel-ai/.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /genai-function-calling/vercel-ai/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22-alpine 2 | 3 | WORKDIR /app 4 | 5 | COPY package.json /app/ 6 | 7 | RUN touch .env && npm install 8 | 9 | COPY *.js /app/ 10 | 11 | ENTRYPOINT ["npm", "start"] 12 | -------------------------------------------------------------------------------- /genai-function-calling/vercel-ai/README.md: -------------------------------------------------------------------------------- 1 | # Function Calling with Vercel AI (Node.js) 2 | 3 | [index.js](index.js) implements the [example application flow][flow] using 4 | [Vercel AI (Node.js)][vercel-ai]. 5 | 6 | [package.json](package.json) starts the application with Elastic Distribution 7 | of OpenTelemetry (EDOT) Node.js, by requiring `@elastic/opentelemetry-node` 8 | 9 | ## Configure 10 | 11 | Copy [env.example](env.example) to `.env` and update its `OPENAI_API_KEY`. 12 | 13 | An OTLP compatible endpoint should be listening for traces, metrics and logs on 14 | `http://localhost:4318`. If not, update `OTEL_EXPORTER_OTLP_ENDPOINT` as well. 15 | 16 | ## Run with Docker 17 | 18 | ```bash 19 | docker compose run --build --rm genai-function-calling 20 | ``` 21 | 22 | ## Run with npm 23 | 24 | ```bash 25 | nvm install --lts 26 | nvm use --lts 27 | npm install 28 | npm start 29 | ``` 30 | 31 | 32 | ## Run with Model Context Protocol (MCP) 33 | 34 | [mcp.js](mcp.js) includes code needed to decouple tool discovery and invocation 35 | via the [Model Context Protocol (MCP) flow][flow-mcp]. To run using MCP, append 36 | `-- --mcp` flag to `npm start` or `docker compose run` command. 37 | 38 | For example, to run with Docker: 39 | ```bash 40 | docker compose run --build --rm genai-function-calling -- --mcp 41 | ``` 42 | 43 | Or to run with npm: 44 | ```bash 45 | npm run start -- --mcp 46 | ``` 47 | 48 | ## Notes 49 | 50 | The LLM should generate something like "The latest stable version of 51 | Elasticsearch is 8.18.0," unless it hallucinates. Run it again, if you see 52 | something else. 53 | 54 | Vercel AI's OpenTelemetry instrumentation only produces traces (not logs or 55 | metrics). 56 | 57 | This uses [OpenInference][openinference] to propagate trace identifiers when 58 | using MCP. 59 | 60 | --- 61 | [flow]: ../README.md#example-application-flow 62 | [vercel-ai]: https://github.com/vercel/ai 63 | [flow-mcp]: ../README.md#model-context-protocol-flow 64 | [openinference]: https://github.com/Arize-ai/openinference/tree/main/js/packages/openinference-instrumentation-mcp 65 | -------------------------------------------------------------------------------- /genai-function-calling/vercel-ai/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | genai-function-calling: 3 | container_name: genai-function-calling 4 | build: 5 | context: ./ 6 | env_file: 7 | - .env 8 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 9 | - "localhost:${HOST_IP:-host-gateway}" 10 | -------------------------------------------------------------------------------- /genai-function-calling/vercel-ai/env.example: -------------------------------------------------------------------------------- 1 | # Update this with your real OpenAI API key 2 | OPENAI_API_KEY= 3 | 4 | # Uncomment to use Ollama instead of OpenAI 5 | # OPENAI_BASE_URL=http://localhost:11434/v1 6 | # OPENAI_API_KEY=unused 7 | # CHAT_MODEL=qwen3:0.6b 8 | 9 | # Uncomment to use RamaLama instead of OpenAI 10 | # OPENAI_BASE_URL=http://localhost:8080/v1 11 | # OPENAI_API_KEY=unused 12 | # CHAT_MODEL=qwen3:0.6b 13 | 14 | # Uncomment and complete if you want to use Azure OpenAI Service 15 | ## "Azure OpenAI Endpoint" in https://oai.azure.com/resource/overview 16 | # AZURE_OPENAI_ENDPOINT=https://YOUR_RESOURCE_NAME.openai.azure.com/ 17 | ## "API key 1 (or 2)" in https://oai.azure.com/resource/overview 18 | # AZURE_OPENAI_API_KEY= 19 | ## "Inference version" from https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation 20 | # OPENAI_API_VERSION=2024-10-01-preview 21 | ## "Name" from https://oai.azure.com/resource/deployments 22 | # CHAT_MODEL=YOUR_DEPLOYMENT_NAME 23 | 24 | # Default to send logs, traces and metrics to an OpenTelemetry collector, 25 | # accessible via localhost. For example, Elastic Distribution of OpenTelemetry 26 | # (EDOT) Collector. 27 | OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 28 | OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 29 | 30 | OTEL_SERVICE_NAME=genai-function-calling 31 | # Don't print status message on startup 32 | OTEL_LOG_LEVEL=warn 33 | -------------------------------------------------------------------------------- /genai-function-calling/vercel-ai/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "genai-function-calling", 3 | "version": "1.0.0", 4 | "private": true, 5 | "type": "commonjs", 6 | "engines": { 7 | "node": ">=22" 8 | }, 9 | "scripts": { 10 | "start": "node --env-file .env --import @elastic/opentelemetry-node --import ./telemetry.js index.js" 11 | }, 12 | "dependencies": { 13 | "ai": "^4.3.11", 14 | "@ai-sdk/azure": "^1.3.21", 15 | "@ai-sdk/openai": "^1.3.20", 16 | "@modelcontextprotocol/sdk": "^1.10.2", 17 | "@elastic/opentelemetry-node": "^1", 18 | "@arizeai/openinference-instrumentation-mcp": "^0.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /genai-function-calling/vercel-ai/telemetry.js: -------------------------------------------------------------------------------- 1 | const { MCPInstrumentation } = require("@arizeai/openinference-instrumentation-mcp"); 2 | 3 | const mcpInstrumentation = new MCPInstrumentation(); 4 | // MCP must be manually instrumented as it doesn't have a traditional module structure 5 | mcpInstrumentation.manuallyInstrument({ 6 | clientStdioModule: require("@modelcontextprotocol/sdk/client/stdio.js"), 7 | serverStdioModule: require("@modelcontextprotocol/sdk/server/stdio.js"), 8 | }); 9 | -------------------------------------------------------------------------------- /inference-platforms/archgw/README.md: -------------------------------------------------------------------------------- 1 | # archgw 2 | 3 | This shows how to use the Arch Gateway as an OpenAI [LLM router][docs], using 4 | its [`tracing` configuration][config] for OpenTelemetry. 5 | 6 | Arch Gateway does not serve OpenAI requests. Rather, it configures an Envoy 7 | proxy according to its configuration. Envoy handles requests, collects 8 | telemetry and forwards them to Ollama via the OpenAI API. 9 | 10 | ## Setup 11 | 12 | Start ollama and the otel collector via this repository's [README](../../README.md). 13 | 14 | ## Run Arch Gateway 15 | 16 | Arch Gateway is a python command that internally runs Docker. Hence, you need a 17 | working Docker configuration. Run `archgw` using `uvx` from [uv][uv]. 18 | 19 | ```bash 20 | uvx archgw up --service archgw --foreground 21 | ``` 22 | 23 | ## Start Prometheus to Elasticsearch pump 24 | 25 | If your OpenTelemetry backend is Elasticsearch, you can pump Prometheus metrics 26 | coming from Arch Gateway to Elasticsearch like this: 27 | 28 | ```bash 29 | docker compose -f docker-compose-elastic.yml run --rm prometheus-pump 30 | ``` 31 | 32 | ## Call Arch Gateway with python 33 | 34 | Once Arch Gateway is running, use [uv][uv] to make an OpenAI request via 35 | [chat.py](../chat.py): 36 | 37 | ```bash 38 | uv run --exact -q --env-file env.local ../chat.py 39 | ``` 40 | 41 | ## Notes 42 | 43 | OpenTelemetry signals are a function of native [Envoy support][envoy-otel] 44 | and anything added in Arch Gateway's [wasm filter][archgw-wasm]. 45 | 46 | * `archgw` invokes `envoy` in a Docker container, which is why this has no 47 | instructions to run from Docker (to avoid nested docker). 48 | * Traces come from Envoy, whose configuration is written by `archgw`. At the 49 | moment, this hard-codes aspects including default ports. 50 | * Until [this][openai-responses] resolves, don't use `--use-responses-api`. 51 | 52 | The chat prompt was designed to be idempotent, but the results are not. You may 53 | see something besides 'South Atlantic Ocean.'. 54 | Just run it again until we find a way to make the results idempotent. 55 | 56 | --- 57 | [docs]: https://github.com/katanemo/archgw?tab=readme-ov-file#use-arch-gateway-as-llm-router 58 | [config]: https://docs.archgw.com/guides/observability/tracing.html 59 | [envoy-otel]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/trace/v3/opentelemetry.proto#extension-envoy-tracers-opentelemetry 60 | [archgw-wasm]: https://github.com/katanemo/archgw/blob/main/arch/README.md 61 | [uv]: https://docs.astral.sh/uv/getting-started/installation/ 62 | [openai-responses]: https://github.com/katanemo/archgw/issues/476 63 | -------------------------------------------------------------------------------- /inference-platforms/archgw/arch_config.yaml: -------------------------------------------------------------------------------- 1 | version: "0.1-beta" 2 | 3 | listeners: 4 | egress_traffic: 5 | address: 0.0.0.0 6 | port: 12000 7 | message_format: openai 8 | timeout: 30s 9 | 10 | llm_providers: 11 | - name: qwen3:0.6b 12 | provider_interface: openai 13 | # This configuration is converted to Envoy and run inside Docker. 14 | endpoint: host.docker.internal:11434 15 | model: qwen3:0.6b 16 | default: true 17 | 18 | tracing: 19 | random_sampling: 100 20 | trace_arch_internal: true 21 | -------------------------------------------------------------------------------- /inference-platforms/archgw/docker-compose-elastic.yml: -------------------------------------------------------------------------------- 1 | configs: 2 | # Configuration is simplified from archgw here: 3 | # https://github.com/katanemo/archgw/blob/main/docs/source/guides/observability/monitoring.rst 4 | # 5 | # Note: The prometheus cluster name for qwen3:0.65b will shows up as '6b' 6 | # See https://github.com/katanemo/archgw/issues/504 7 | prometheus-pump-config: 8 | content: | 9 | receivers: 10 | prometheus: 11 | config: 12 | global: 13 | evaluation_interval: 5s 14 | scrape_configs: 15 | - job_name: 'archgw' 16 | honor_timestamps: true 17 | scrape_interval: 5s 18 | scrape_timeout: 5s 19 | metrics_path: /stats 20 | static_configs: 21 | - targets: ['localhost:19901'] 22 | params: 23 | format: ["prometheus"] 24 | 25 | processors: 26 | # Elastic Stack doesn't currently support cumulative metrics 27 | cumulativetodelta: 28 | 29 | exporters: 30 | elasticsearch: 31 | endpoint: http://localhost:9200 32 | user: elastic 33 | password: elastic 34 | mapping: 35 | mode: otel 36 | metrics_dynamic_index: 37 | enabled: true 38 | flush: 39 | interval: 1s # improve responsiveness in example apps (default 30s) 40 | 41 | service: 42 | pipelines: 43 | metrics: 44 | receivers: [prometheus] 45 | processors: [cumulativetodelta] 46 | exporters: [elasticsearch] 47 | 48 | services: 49 | # prometheus-pump is an OpenTelemetry Collector that scrapes Prometheus metrics 50 | prometheus-pump: 51 | # TODO: Use EDOT after https://github.com/elastic/elastic-agent/pull/8372 52 | image: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib:0.127.0 53 | container_name: prometheus-pump 54 | command: [ 55 | "--config=/etc/otel/config.yaml", 56 | ] 57 | configs: 58 | - source: prometheus-pump-config 59 | target: /etc/otel/config.yaml 60 | mode: 0444 61 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 62 | - "localhost:host-gateway" 63 | 64 | -------------------------------------------------------------------------------- /inference-platforms/archgw/env.local: -------------------------------------------------------------------------------- 1 | # Arch gateway endpoint 2 | OPENAI_BASE_URL=http://localhost:12000/v1 3 | OPENAI_API_KEY=unused 4 | CHAT_MODEL=qwen3:0.6B 5 | 6 | OTEL_SERVICE_NAME=archgw 7 | 8 | # Disable resource detectors by default 9 | OTEL_PYTHON_DISABLED_RESOURCE_DETECTORS=all 10 | -------------------------------------------------------------------------------- /inference-platforms/chat.py: -------------------------------------------------------------------------------- 1 | # /// script 2 | # dependencies = [ 3 | # "openai", 4 | # "elastic-opentelemetry", 5 | # "openinference-instrumentation-openai", 6 | # "opentelemetry-instrumentation-httpx" 7 | # ] 8 | # /// 9 | import argparse 10 | import os 11 | 12 | import openai 13 | from opentelemetry.instrumentation import auto_instrumentation 14 | 15 | auto_instrumentation.initialize() 16 | 17 | model = os.getenv("CHAT_MODEL", "gpt-4o-mini") 18 | 19 | 20 | def main(): 21 | parser = argparse.ArgumentParser(description="OpenTelemetry-Enabled OpenAI Test Client") 22 | parser.add_argument( 23 | "--use-responses-api", action="store_true", help="Use the responses API instead of chat completions." 24 | ) 25 | args = parser.parse_args() 26 | 27 | client = openai.Client() 28 | 29 | messages = [ 30 | { 31 | "role": "user", 32 | "content": "Answer in up to 3 words: Which ocean contains Bouvet Island?", 33 | } 34 | ] 35 | 36 | # vllm-specific switch to disable thinking, ignored by other inference platforms. 37 | # See https://qwen.readthedocs.io/en/latest/deployment/vllm.html#thinking-non-thinking-modes 38 | if "qwen3" in model.lower(): 39 | extra_body = {"chat_template_kwargs": {"enable_thinking": False}} 40 | else: 41 | extra_body = {} 42 | if args.use_responses_api: 43 | response = client.responses.create( 44 | model=model, input=messages[0]["content"], temperature=0, extra_body=extra_body 45 | ) 46 | print(response.output[0].content[0].text) 47 | else: 48 | chat_completion = client.chat.completions.create( 49 | model=model, messages=messages, temperature=0, extra_body=extra_body 50 | ) 51 | print(chat_completion.choices[0].message.content) 52 | 53 | 54 | if __name__ == "__main__": 55 | main() 56 | -------------------------------------------------------------------------------- /inference-platforms/kibana-trace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/inference-platforms/kibana-trace.jpg -------------------------------------------------------------------------------- /inference-platforms/litellm/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use glibc-based image with pre-compiled wheels for psutil 2 | FROM python:3.13-slim 3 | 4 | RUN python -m pip install --upgrade pip 5 | RUN pip install \ 6 | # litellm proxy requirements 7 | litellm[proxy]~=1.72.1 \ 8 | opentelemetry-exporter-otlp-proto-http~=1.34.0 \ 9 | # TODO: required until https://github.com/BerriAI/litellm/issues/9901 10 | opentelemetry-exporter-otlp-proto-grpc~=1.34.0 11 | 12 | COPY config.yaml / 13 | 14 | EXPOSE 4000 15 | 16 | CMD [ "litellm", "-c", "config.yaml", "--detailed_debug" ] 17 | -------------------------------------------------------------------------------- /inference-platforms/litellm/README.md: -------------------------------------------------------------------------------- 1 | # LiteLLM 2 | 3 | This shows how to use the LiteLLM Proxy Server as an [OpenAI gateway][docs], 4 | using its [`otel` logging callback][config] for OpenTelemetry. 5 | 6 | Requests to the proxy are logged and forwarded to Ollama via the OpenAI API. 7 | The `otel` logging callback use the OpenTelemetry Python SDK to export traces. 8 | 9 | ## Prerequisites 10 | 11 | Start Ollama and your OpenTelemetry Collector via this repository's [README](../README.md). 12 | 13 | ## Run LiteLLM 14 | 15 | ```bash 16 | docker compose up --build --force-recreate --remove-orphans 17 | ``` 18 | 19 | Clean up when finished, like this: 20 | 21 | ```bash 22 | docker compose down 23 | ``` 24 | 25 | ## Call LiteLLM with python 26 | 27 | Once LiteLLM is running, use [uv][uv] to make an OpenAI request via 28 | [chat.py](../chat.py): 29 | 30 | ```bash 31 | # Set the OpenAI base URL to the LiteLLM proxy, not Ollama 32 | OPENAI_BASE_URL=http://localhost:4000/v1 uv run --exact -q --env-file env.local ../chat.py 33 | ``` 34 | 35 | ## Notes 36 | 37 | * LiteLLM uses its callbacks, not `opentelemetry-instrument`, to instrument 38 | calls. This prevents propagation from working. 39 | * LiteLLM uses [custom env][env] to configure OTLP and the tracer. This means 40 | `opentelemetry-instrument` can't configure it. 41 | * LiteLLM makes spurious HTTP requests to its [pricing endpoint][endpoint], 42 | which shows up as an extra trace when in use. 43 | * `--use-responses-api` only works when what you are proxying supports it. In 44 | other words, it doesn't work with Ollama unless Ollama adds responses API. 45 | 46 | --- 47 | [docs]: https://docs.litellm.ai/docs/simple_proxy 48 | [config]: https://github.com/BerriAI/litellm/blob/main/litellm/integrations/opentelemetry.py 49 | [uv]: https://docs.astral.sh/uv/getting-started/installation/ 50 | [sdk]: https://github.com/BerriAI/litellm/blob/main/litellm/main.py 51 | [env]: https://github.com/BerriAI/litellm/issues/9901 52 | [endpoint]: https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json -------------------------------------------------------------------------------- /inference-platforms/litellm/config.yaml: -------------------------------------------------------------------------------- 1 | model_list: 2 | - model_name: "*" 3 | litellm_params: 4 | model: openai/* 5 | api_base: os.environ/OPENAI_BASE_URL 6 | api_key: os.environ/OPENAI_API_KEY 7 | 8 | litellm_settings: 9 | callbacks: ["otel"] 10 | 11 | -------------------------------------------------------------------------------- /inference-platforms/litellm/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | litellm: 3 | container_name: litellm 4 | build: 5 | context: . 6 | env_file: 7 | - env.local 8 | ports: 9 | - "4000:4000" 10 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 11 | - "localhost:host-gateway" 12 | -------------------------------------------------------------------------------- /inference-platforms/litellm/env.local: -------------------------------------------------------------------------------- 1 | # Override default ENV variables for Ollama 2 | OPENAI_BASE_URL=http://localhost:11434/v1 3 | OPENAI_API_KEY=unused 4 | CHAT_MODEL=qwen3:0.6B 5 | 6 | # OpenTelemetry configuration 7 | OTEL_SERVICE_NAME=litellm 8 | # LiteLLM uses custom ENV until https://github.com/BerriAI/litellm/issues/9901 9 | OTEL_EXPORTER=otlp_http 10 | OTEL_ENDPOINT=http://localhost:4318/v1/traces 11 | 12 | # Disable resource detectors by default 13 | OTEL_PYTHON_DISABLED_RESOURCE_DETECTORS=all 14 | -------------------------------------------------------------------------------- /inference-platforms/llama-stack/README.md: -------------------------------------------------------------------------------- 1 | # Llama Stack 2 | 3 | This shows how to use [Llama Stack][docs] to proxy Ollama, accessible via an 4 | OpenAI compatible API. 5 | 6 | This uses the [`otel` telemetry sink][otel-sink] to export OpenTelemetry traces 7 | and metrics from signals recorded with Llama Stack's observability SDK. 8 | 9 | ## Prerequisites 10 | 11 | Start Ollama and your OpenTelemetry Collector via this repository's [README](../README.md). 12 | 13 | ## Run Llama Stack 14 | 15 | ```bash 16 | docker compose up --pull always --force-recreate --remove-orphans 17 | ``` 18 | 19 | Clean up when finished, like this: 20 | 21 | ```bash 22 | docker compose down 23 | ``` 24 | 25 | ## Call Llama Stack with python 26 | 27 | Once Llama Stack is running, use [uv][uv] to make an OpenAI request via 28 | [chat.py](../chat.py): 29 | 30 | ```bash 31 | uv run --exact -q --env-file env.local ../chat.py 32 | ``` 33 | 34 | Or, for the OpenAI Responses API 35 | ```bash 36 | uv run --exact -q --env-file env.local ../chat.py --use-responses-api 37 | ``` 38 | 39 | ## Notes 40 | 41 | Here are some constraints about the LlamaStack implementation: 42 | * Only supports llama models (so not Qwen) 43 | * Bridges its tracing and metrics APIs to `otel_trace` and `otel_metric` sinks. 44 | * Until [this issue][docker] resolves, running docker on Apple Silicon 45 | requires emulation. 46 | * Llama Stack doesn't yet have ENV variable support for the OTLP exporter. 47 | Hence, we use Docker's localhost:host-gateway to direct localhost traffic 48 | back to the host. See https://github.com/meta-llama/llama-stack/issues/783 49 | 50 | --- 51 | [docs]: https://llama-stack.readthedocs.io/en/latest/index.html 52 | [otel-sink]: https://llama-stack.readthedocs.io/en/latest/building_applications/telemetry.html#configuration 53 | [uv]: https://docs.astral.sh/uv/getting-started/installation/ 54 | [docker]: https://github.com/meta-llama/llama-stack/issues/406 55 | -------------------------------------------------------------------------------- /inference-platforms/llama-stack/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | ollama-pull: 3 | image: alpine/ollama 4 | container_name: ollama-pull 5 | environment: 6 | OLLAMA_HOST: localhost:11434 # instead of IP 127.0.0.1 7 | env_file: 8 | - env.local 9 | entrypoint: sh 10 | command: -c 'env | grep _MODEL | cut -d= -f2 | xargs -I{} ollama pull {}' 11 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 12 | - "localhost:host-gateway" 13 | 14 | llama-stack: 15 | depends_on: 16 | ollama-pull: 17 | condition: service_completed_successfully 18 | image: llamastack/distribution-ollama:0.2.9 19 | container_name: llama-stack 20 | tty: true 21 | env_file: 22 | - env.local 23 | ports: 24 | - "8321:8321" 25 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 26 | - "localhost:host-gateway" 27 | -------------------------------------------------------------------------------- /inference-platforms/llama-stack/env.local: -------------------------------------------------------------------------------- 1 | # Override default ENV variables for llama-stack 2 | OPENAI_BASE_URL=http://localhost:8321/v1/openai/v1 3 | OPENAI_API_KEY=unused 4 | CHAT_MODEL=llama3.2:1b 5 | 6 | # Variable name used by llama-stack 7 | INFERENCE_MODEL=llama3.2:1b 8 | 9 | # OpenTelemetry configuration 10 | TELEMETRY_SINKS=otel_trace,otel_metric 11 | # Note: there's not yet ENV variable support for endpoints 12 | # See https://github.com/meta-llama/llama-stack/issues/783 13 | 14 | OTEL_SERVICE_NAME=llama-stack 15 | # Disable resource detectors by default 16 | OTEL_PYTHON_DISABLED_RESOURCE_DETECTORS=all 17 | -------------------------------------------------------------------------------- /inference-platforms/open-responses/README.md: -------------------------------------------------------------------------------- 1 | # open-responses 2 | 3 | This shows how to use the Masaic OpenResponses as an [OpenAI Responses adapter][docs], 4 | using its [OpenTelemetry configuration][config]. 5 | 6 | OpenAI Responses API requests are adapted and forwarded to Ollama as chat 7 | completions. 8 | 9 | ## Prerequisites 10 | 11 | Start Ollama and your OpenTelemetry Collector via this repository's [README](../README.md). 12 | 13 | ## Run OpenResponses 14 | 15 | ```bash 16 | docker compose up --pull always --force-recreate --remove-orphans 17 | ``` 18 | 19 | Clean up when finished, like this: 20 | 21 | ```bash 22 | docker compose down 23 | ``` 24 | 25 | ## Call OpenResponses with python 26 | 27 | Once OpenResponses is running, use [uv][uv] to make an OpenAI request via 28 | [chat.py](../chat.py): 29 | 30 | ```bash 31 | # Set the OpenAI base URL to the OpenResponses proxy, not Ollama 32 | OPENAI_BASE_URL=http://localhost:8080/v1 uv run --exact -q --env-file env.local ../chat.py 33 | ``` 34 | 35 | Or, for the OpenAI Responses API 36 | ```bash 37 | OPENAI_BASE_URL=http://localhost:8080/v1 uv run --exact -q --env-file env.local ../chat.py --use-responses-api 38 | ``` 39 | 40 | ## Notes 41 | 42 | OpenResponses is a Spring Boot application, so signals collected are adapted to 43 | OpenTelemetry via a Micrometer bridge. 44 | 45 | --- 46 | [doc]: https://openresponses.masaic.ai/openresponses/compatibility 47 | [config]: https://openresponses.masaic.ai/openresponses/observability#setting-up-the-opentelemetry-collector 48 | [uv]: https://docs.astral.sh/uv/getting-started/installation/ 49 | -------------------------------------------------------------------------------- /inference-platforms/open-responses/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | open-responses: 3 | image: masaicai/open-responses:0.3.2 4 | container_name: open-responses 5 | env_file: 6 | - env.local 7 | ports: 8 | - "8080:8080" 9 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 10 | - "localhost:host-gateway" 11 | -------------------------------------------------------------------------------- /inference-platforms/open-responses/env.local: -------------------------------------------------------------------------------- 1 | OPENAI_BASE_URL=http://localhost:11434/v1 2 | OPENAI_API_KEY=unused 3 | CHAT_MODEL=qwen3:0.6B 4 | 5 | # Disabled by default in open-responses 6 | OTEL_SDK_DISABLED=false 7 | 8 | OTEL_SERVICE_NAME=open-responses 9 | OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 10 | OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 11 | 12 | # Disable resource detectors by default 13 | OTEL_PYTHON_DISABLED_RESOURCE_DETECTORS=all 14 | -------------------------------------------------------------------------------- /inference-platforms/vllm/README.md: -------------------------------------------------------------------------------- 1 | # vLLM 2 | 3 | This shows how to use the [vLLM OpenTelemetry POC][otel-poc] to export 4 | OpenTelemetry traces from vLLM requests to its OpenAI compatible endpoint. 5 | 6 | ## Prerequisites 7 | 8 | Start Ollama and your OpenTelemetry Collector via this repository's [README](../README.md). 9 | 10 | ## Run vLLM 11 | 12 | ```bash 13 | docker compose up --build --force-recreate --remove-orphans 14 | ``` 15 | 16 | Clean up when finished, like this: 17 | 18 | ```bash 19 | docker compose down 20 | ``` 21 | 22 | ## Call vLLM with python 23 | 24 | Once vLLM is running, use [uv][uv] to make an OpenAI request via 25 | [chat.py](../chat.py): 26 | 27 | ```bash 28 | uv run --exact -q --env-file env.local ../chat.py 29 | ``` 30 | 31 | ## Notes 32 | 33 | * This does not yet support metrics, and there is no GitHub issue on it. 34 | * This does not yet support logs, and there is no GitHub issue on it. 35 | * Until [this][openai-responses] resolves, don't use `--use-responses-api`. 36 | 37 | --- 38 | [otel-poc]: https://github.com/vllm-project/vllm/blob/main/examples/online_serving/opentelemetry/README.md 39 | [uv]: https://docs.astral.sh/uv/getting-started/installation/ 40 | [openai-responses]: https://github.com/vllm-project/vllm/issues/14721 41 | -------------------------------------------------------------------------------- /inference-platforms/vllm/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | vllm: 3 | container_name: vllm 4 | build: 5 | context: . 6 | env_file: 7 | - env.local 8 | ports: 9 | - "8000:8000" 10 | extra_hosts: # send localhost traffic to the docker host, e.g. your laptop 11 | - "localhost:host-gateway" 12 | -------------------------------------------------------------------------------- /inference-platforms/vllm/env.local: -------------------------------------------------------------------------------- 1 | # Override default ENV variables for vLLM 2 | OPENAI_BASE_URL=http://localhost:8000/v1 3 | OPENAI_API_KEY=unused 4 | CHAT_MODEL=Qwen/Qwen3-0.6B 5 | 6 | # OpenTelemetry configuration 7 | OTEL_SERVICE_NAME=vllm 8 | 9 | # Note: vLLM only reads traces ENV variables 10 | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces 11 | OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf 12 | OTEL_EXPORTER_OTLP_TRACES_INSECURE=true 13 | 14 | # Disable resource detectors by default 15 | OTEL_PYTHON_DISABLED_RESOURCE_DETECTORS=all 16 | -------------------------------------------------------------------------------- /langchainChat/ENV: -------------------------------------------------------------------------------- 1 | #Azure 2 | export AZURE_OPENAI_API_KEY=YYYY 3 | export AZURE_OPENAI_ENDPOINT="ZZZZZ" 4 | export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-global" 5 | export AZURE_OPENAI_API_VERSION="2024-02-15-preview" 6 | 7 | #OTel 8 | export OTEL_EXPORTER_OTLP_ENDPOINT=XXX:443 9 | export OTEL_EXPORTER_OTLP_HEADERS=""Authorization=Bearer%YYY"" 10 | export OTEL_RESOURCE_ATTRIBUTES="service.name=langchainChat,service.version=1.0,deployment.environment=production" 11 | export OTEL_SERVICE_NAME=langchainChat 12 | -------------------------------------------------------------------------------- /langchainChat/img/SCR-20240816-icwt-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/langchainChat/img/SCR-20240816-icwt-2.png -------------------------------------------------------------------------------- /langchainChat/img/Xnapper-2024-08-16-12.36.03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/observability-examples/1b164009c55967e5da4e2214420fc743d708968e/langchainChat/img/Xnapper-2024-08-16-12.36.03.png -------------------------------------------------------------------------------- /langchainChat/requirements.txt: -------------------------------------------------------------------------------- 1 | python-dotenv 2 | opentelemetry-exporter-otlp-proto-http 3 | langtrace_python_sdk 4 | langchain 5 | langchain_openai 6 | langchain_community 7 | duckduckgo-search -------------------------------------------------------------------------------- /lychee.toml: -------------------------------------------------------------------------------- 1 | include_fragments = false 2 | exclude_all_private = true 3 | 4 | accept = [ 5 | "200..=299", 6 | # Consider a 403 to be success. Cloudflare-protected sites, like 7 | # https://platform.openai.com, return a 403 to lychee. 8 | "403" 9 | ] 10 | 11 | exclude = [ 12 | # OPENAI_BASE_URL is 404 13 | "https://api.openai.com/v1", 14 | # Exclude links replaced by %PUBLIC_URL% 15 | ".*%25PUBLIC_URL%25.*" 16 | ] 17 | 18 | # better to be safe and avoid failures 19 | max_retries = 6 20 | --------------------------------------------------------------------------------