Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ dependencies = [
"fastembed>=0.7.4",
"sqlite-vec>=0.1.6",
"openai>=1.100.2",
"logfire>=4.19.0",
]

[project.urls]
Expand All @@ -58,9 +59,6 @@ Documentation = "https://github.com/basicmachines-co/basic-memory#readme"
basic-memory = "basic_memory.cli.main:app"
bm = "basic_memory.cli.main:app"

[project.optional-dependencies]
telemetry = ["logfire>=4.19.0"]

[build-system]
requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"]
build-backend = "hatchling.build"
Expand Down
6 changes: 3 additions & 3 deletions src/basic_memory/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
list_projects,
synchronize_projects,
)
from basic_memory import telemetry
import logfire
from basic_memory.config import init_api_logging
from basic_memory.services.exceptions import EntityAlreadyExistsError
from basic_memory.services.initialization import initialize_app
Expand All @@ -44,7 +44,7 @@ async def lifespan(app: FastAPI): # pragma: no cover
set_container(container)
app.state.container = container

with telemetry.operation(
with logfire.span(
"api.lifecycle.startup",
entrypoint="api",
mode=container.mode.name.lower(),
Expand All @@ -69,7 +69,7 @@ async def lifespan(app: FastAPI): # pragma: no cover
yield

# Shutdown - coordinator handles clean task cancellation
with telemetry.operation(
with logfire.span(
"api.lifecycle.shutdown",
entrypoint="api",
mode=container.mode.name.lower(),
Expand Down
22 changes: 11 additions & 11 deletions src/basic_memory/api/v2/routers/knowledge_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from fastapi import APIRouter, HTTPException, Response, Path
from loguru import logger

from basic_memory import telemetry
import logfire
from basic_memory.deps import (
EntityServiceV2ExternalDep,
SearchServiceV2ExternalDep,
Expand Down Expand Up @@ -74,7 +74,7 @@ async def get_graph(
Returns a flat node/edge structure optimized for rendering with graph libraries.
Only includes resolved relations (where to_id is not null).
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.get_graph",
entrypoint="api",
domain="knowledge",
Expand Down Expand Up @@ -148,7 +148,7 @@ async def resolve_identifier(
"resolution_method": "permalink"
}
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.resolve_entity",
entrypoint="api",
domain="knowledge",
Expand Down Expand Up @@ -215,7 +215,7 @@ async def get_entity_by_id(
Raises:
HTTPException: 404 if entity not found
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.get_entity",
entrypoint="api",
domain="knowledge",
Expand Down Expand Up @@ -255,7 +255,7 @@ async def create_entity(
Returns:
Created entity with generated external_id (UUID) and file content
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.create_entity",
entrypoint="api",
domain="knowledge",
Expand Down Expand Up @@ -313,7 +313,7 @@ async def update_entity_by_id(
Returns:
Updated entity with file content
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.update_entity",
entrypoint="api",
domain="knowledge",
Expand Down Expand Up @@ -385,7 +385,7 @@ async def edit_entity_by_id(
Raises:
HTTPException: 404 if entity not found, 400 if edit fails
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.edit_entity",
entrypoint="api",
domain="knowledge",
Expand Down Expand Up @@ -454,7 +454,7 @@ async def delete_entity_by_id(

Note: Returns deleted=False if entity doesn't exist (idempotent)
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.delete_entity",
entrypoint="api",
domain="knowledge",
Expand Down Expand Up @@ -503,7 +503,7 @@ async def move_entity(
Returns:
Updated entity with new file path
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.move_entity",
entrypoint="api",
domain="knowledge",
Expand Down Expand Up @@ -583,7 +583,7 @@ async def move_directory(
Returns:
DirectoryMoveResult with counts and details of moved files
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.move_directory",
entrypoint="api",
domain="knowledge",
Expand Down Expand Up @@ -647,7 +647,7 @@ async def delete_directory(
Returns:
DirectoryDeleteResult with counts and details of deleted files
"""
with telemetry.operation(
with logfire.span(
"api.request.knowledge.delete_directory",
entrypoint="api",
domain="knowledge",
Expand Down
14 changes: 7 additions & 7 deletions src/basic_memory/api/v2/routers/memory_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from fastapi import APIRouter, Query, Path
from loguru import logger

from basic_memory import telemetry
import logfire
from basic_memory.deps import ContextServiceV2ExternalDep, EntityRepositoryV2ExternalDep
from basic_memory.schemas.base import TimeFrame, parse_timeframe
from basic_memory.schemas.memory import (
Expand Down Expand Up @@ -51,7 +51,7 @@ async def recent(
Returns:
GraphContext with recent activity and related entities
"""
with telemetry.operation(
with logfire.span(
"api.request.memory.recent_activity",
entrypoint="api",
domain="memory",
Expand All @@ -72,7 +72,7 @@ async def recent(
limit = page_size
offset = (page - 1) * page_size

with telemetry.scope(
with logfire.span(
"api.memory.recent_activity.build_context",
domain="memory",
action="recent_activity",
Expand All @@ -88,7 +88,7 @@ async def recent(
offset=offset,
max_related=max_related,
)
with telemetry.scope(
with logfire.span(
"api.memory.recent_activity.shape_response",
domain="memory",
action="recent_activity",
Expand Down Expand Up @@ -137,7 +137,7 @@ async def get_memory_context(
Returns:
GraphContext with the entity and its related context
"""
with telemetry.operation(
with logfire.span(
"api.request.memory.build_context",
entrypoint="api",
domain="memory",
Expand All @@ -154,7 +154,7 @@ async def get_memory_context(
limit = page_size
offset = (page - 1) * page_size

with telemetry.scope(
with logfire.span(
"api.memory.build_context.build_context",
domain="memory",
action="build_context",
Expand All @@ -170,7 +170,7 @@ async def get_memory_context(
offset=offset,
max_related=max_related,
)
with telemetry.scope(
with logfire.span(
"api.memory.build_context.shape_response",
domain="memory",
action="build_context",
Expand Down
32 changes: 16 additions & 16 deletions src/basic_memory/api/v2/routers/resource_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from fastapi import APIRouter, HTTPException, Response, Path
from loguru import logger

from basic_memory import telemetry
import logfire
from basic_memory.deps import (
ProjectConfigV2ExternalDep,
FileServiceV2ExternalDep,
Expand Down Expand Up @@ -56,15 +56,15 @@ async def get_resource_content(
Raises:
HTTPException: 404 if entity or file not found
"""
with telemetry.operation(
with logfire.span(
"api.request.resource.get_content",
entrypoint="api",
domain="resource",
action="get_content",
):
logger.debug(f"V2 Getting content for project {project_id}, entity_id: {entity_id}")

with telemetry.scope(
with logfire.span(
"api.resource.get_content.load_entity",
domain="resource",
action="get_content",
Expand All @@ -74,7 +74,7 @@ async def get_resource_content(
if not entity:
raise HTTPException(status_code=404, detail=f"Entity {entity_id} not found")

with telemetry.scope(
with logfire.span(
"api.resource.get_content.validate_path",
domain="resource",
action="get_content",
Expand All @@ -90,7 +90,7 @@ async def get_resource_content(
detail="Entity contains invalid file path",
)

with telemetry.scope(
with logfire.span(
"api.resource.get_content.ensure_exists",
domain="resource",
action="get_content",
Expand All @@ -102,7 +102,7 @@ async def get_resource_content(
detail=f"File not found: {entity.file_path}",
)

with telemetry.scope(
with logfire.span(
"api.resource.get_content.read_content",
domain="resource",
action="get_content",
Expand Down Expand Up @@ -139,7 +139,7 @@ async def create_resource(
Raises:
HTTPException: 400 for invalid file paths, 409 if file already exists
"""
with telemetry.operation(
with logfire.span(
"api.request.resource.create",
entrypoint="api",
domain="resource",
Expand All @@ -166,7 +166,7 @@ async def create_resource(
f"Use PUT /resource/{existing_entity.external_id} to update it.",
)

with telemetry.scope(
with logfire.span(
"api.resource.create.write_file",
domain="resource",
action="create",
Expand All @@ -175,7 +175,7 @@ async def create_resource(
await file_service.ensure_directory(PathLib(data.file_path).parent)
checksum = await file_service.write_file(data.file_path, data.content)

with telemetry.scope(
with logfire.span(
"api.resource.create.read_metadata",
domain="resource",
action="create",
Expand All @@ -197,15 +197,15 @@ async def create_resource(
created_at=file_metadata.created_at,
updated_at=file_metadata.modified_at,
)
with telemetry.scope(
with logfire.span(
"api.resource.create.upsert_entity",
domain="resource",
action="create",
phase="upsert_entity",
):
entity = await entity_repository.add(entity)

with telemetry.scope(
with logfire.span(
"api.resource.create.search_index",
domain="resource",
action="create",
Expand Down Expand Up @@ -258,7 +258,7 @@ async def update_resource(
Raises:
HTTPException: 404 if entity not found, 400 for invalid paths
"""
with telemetry.operation(
with logfire.span(
"api.request.resource.update",
entrypoint="api",
domain="resource",
Expand All @@ -282,7 +282,7 @@ async def update_resource(
"Path must be relative and stay within project boundaries.",
)

with telemetry.scope(
with logfire.span(
"api.resource.update.write_file",
domain="resource",
action="update",
Expand All @@ -297,7 +297,7 @@ async def update_resource(

checksum = await file_service.write_file(target_file_path, data.content)

with telemetry.scope(
with logfire.span(
"api.resource.update.read_metadata",
domain="resource",
action="update",
Expand All @@ -309,7 +309,7 @@ async def update_resource(
content_type = file_service.content_type(target_file_path)
note_type = "canvas" if target_file_path.endswith(".canvas") else "file"

with telemetry.scope(
with logfire.span(
"api.resource.update.update_entity",
domain="resource",
action="update",
Expand All @@ -329,7 +329,7 @@ async def update_resource(
if updated_entity is None:
raise HTTPException(status_code=404, detail=f"Entity {entity_id} not found")

with telemetry.scope(
with logfire.span(
"api.resource.update.search_index",
domain="resource",
action="update",
Expand Down
Loading
Loading