From ee2cc66c3bd7128daa0d10065c9573e5a65a7be6 Mon Sep 17 00:00:00 2001
From: Nir Gazit <nirga@users.noreply.github.com>
Date: Mon, 8 Apr 2024 05:19:00 +0200
Subject: [PATCH] feat: observability for Python with OpenTelemetry (#39)

---
 helpers/python.ts                             | 21 ++++++++++
 questions.ts                                  | 40 +++++++++----------
 .../python/opentelemetry/observability.py     |  5 +++
 .../streaming/fastapi/app/observability.py    |  2 +
 templates/types/streaming/fastapi/main.py     |  2 +
 5 files changed, 49 insertions(+), 21 deletions(-)
 create mode 100644 templates/components/observability/python/opentelemetry/observability.py
 create mode 100644 templates/types/streaming/fastapi/app/observability.py

diff --git a/helpers/python.ts b/helpers/python.ts
index 5b240ce1..af83dd2c 100644
--- a/helpers/python.ts
+++ b/helpers/python.ts
@@ -206,6 +206,7 @@ export const installPythonTemplate = async ({
   tools,
   postInstallAction,
   useLlamaParse,
+  observability,
 }: Pick<
   InstallTemplateArgs,
   | "root"
@@ -216,6 +217,7 @@ export const installPythonTemplate = async ({
   | "tools"
   | "useLlamaParse"
   | "postInstallAction"
+  | "observability"
 >) => {
   console.log("\nInitializing Python project with template:", template, "\n");
   const templatePath = path.join(templatesDir, "types", template, framework);
@@ -258,6 +260,25 @@ export const installPythonTemplate = async ({
   const addOnDependencies = dataSources
     .map((ds) => getAdditionalDependencies(vectorDb, ds, tools))
     .flat();
+
+  if (observability === "opentelemetry") {
+    addOnDependencies.push({
+      name: "traceloop-sdk",
+      version: "^0.15.11",
+    });
+
+    const templateObservabilityPath = path.join(
+      templatesDir,
+      "components",
+      "observability",
+      "python",
+      "opentelemetry",
+    );
+    await copy("**", path.join(root, "app"), {
+      cwd: templateObservabilityPath,
+    });
+  }
+
   await addDependencies(root, addOnDependencies);
 
   if (postInstallAction === "runApp" || postInstallAction === "dependencies") {
diff --git a/questions.ts b/questions.ts
index 3ad02d9d..6532882b 100644
--- a/questions.ts
+++ b/questions.ts
@@ -510,28 +510,26 @@ export const askQuestions = async (
     }
   }
 
-  if (program.framework === "express" || program.framework === "nextjs") {
-    if (!program.observability) {
-      if (ciInfo.isCI) {
-        program.observability = getPrefOrDefault("observability");
-      } else {
-        const { observability } = await prompts(
-          {
-            type: "select",
-            name: "observability",
-            message: "Would you like to set up observability?",
-            choices: [
-              { title: "No", value: "none" },
-              { title: "OpenTelemetry", value: "opentelemetry" },
-            ],
-            initial: 0,
-          },
-          handlers,
-        );
+  if (!program.observability) {
+    if (ciInfo.isCI) {
+      program.observability = getPrefOrDefault("observability");
+    } else {
+      const { observability } = await prompts(
+        {
+          type: "select",
+          name: "observability",
+          message: "Would you like to set up observability?",
+          choices: [
+            { title: "No", value: "none" },
+            { title: "OpenTelemetry", value: "opentelemetry" },
+          ],
+          initial: 0,
+        },
+        handlers,
+      );
 
-        program.observability = observability;
-        preferences.observability = observability;
-      }
+      program.observability = observability;
+      preferences.observability = observability;
     }
   }
 
diff --git a/templates/components/observability/python/opentelemetry/observability.py b/templates/components/observability/python/opentelemetry/observability.py
new file mode 100644
index 00000000..046d714e
--- /dev/null
+++ b/templates/components/observability/python/opentelemetry/observability.py
@@ -0,0 +1,5 @@
+from traceloop.sdk import Traceloop
+
+
+def init_observability():
+    Traceloop.init()
diff --git a/templates/types/streaming/fastapi/app/observability.py b/templates/types/streaming/fastapi/app/observability.py
new file mode 100644
index 00000000..28019c37
--- /dev/null
+++ b/templates/types/streaming/fastapi/app/observability.py
@@ -0,0 +1,2 @@
+def init_observability():
+    pass
diff --git a/templates/types/streaming/fastapi/main.py b/templates/types/streaming/fastapi/main.py
index 4ffd54f3..1a4e58be 100644
--- a/templates/types/streaming/fastapi/main.py
+++ b/templates/types/streaming/fastapi/main.py
@@ -10,11 +10,13 @@ from fastapi.middleware.cors import CORSMiddleware
 from fastapi.responses import RedirectResponse
 from app.api.routers.chat import chat_router
 from app.settings import init_settings
+from app.observability import init_observability
 
 
 app = FastAPI()
 
 init_settings()
+init_observability()
 
 environment = os.getenv("ENVIRONMENT", "dev")  # Default to 'development' if not set
 
-- 
GitLab