Skip to content

Commit

Permalink
add logfire.logfire_info() (#826)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Hall <[email protected]>
  • Loading branch information
samuelcolvin and alexmojaki authored Feb 3, 2025
1 parent bb7913b commit 9a51e15
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 56 deletions.
8 changes: 7 additions & 1 deletion .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ body:
**Don't worry if you can't run this command or don't have this information, we'll help you if we can.**
Please run the following command and copy the output below:
Please run the following command in your terminal:
```bash
logfire info
```
Or in python run:
```python
import logfire; print(logfire.logfire_info())
```
render: TOML
4 changes: 4 additions & 0 deletions logfire-api/logfire_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,7 @@ def __init__(self, *args, **kwargs) -> None: ...

class LogfireLoggingHandler:
def __init__(self, *args, **kwargs) -> None: ...

def logfire_info() -> str:
"""Show versions of logfire, OS and related packages."""
return 'logfire_info() is not implement by logfire-api'
3 changes: 2 additions & 1 deletion logfire-api/logfire_api/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from ._internal.auto_trace import AutoTraceModule as AutoTraceModule
from ._internal.auto_trace.rewrite_ast import no_auto_trace as no_auto_trace
from ._internal.cli import logfire_info as logfire_info
from ._internal.config import AdvancedOptions as AdvancedOptions, CodeSource as CodeSource, ConsoleOptions as ConsoleOptions, MetricsOptions as MetricsOptions, PydanticPlugin as PydanticPlugin, configure as configure
from ._internal.constants import LevelName as LevelName
from ._internal.main import Logfire as Logfire, LogfireSpan as LogfireSpan
Expand All @@ -12,7 +13,7 @@ from .version import VERSION as VERSION
from logfire.sampling import SamplingOptions as SamplingOptions
from typing import Any

__all__ = ['Logfire', 'LogfireSpan', 'LevelName', 'AdvancedOptions', 'ConsoleOptions', 'CodeSource', 'PydanticPlugin', 'configure', 'span', 'instrument', 'log', 'trace', 'debug', 'notice', 'info', 'warn', 'warning', 'error', 'exception', 'fatal', 'force_flush', 'log_slow_async_callbacks', 'install_auto_tracing', 'instrument_asgi', 'instrument_wsgi', 'instrument_pydantic', 'instrument_fastapi', 'instrument_openai', 'instrument_anthropic', 'instrument_asyncpg', 'instrument_httpx', 'instrument_celery', 'instrument_requests', 'instrument_psycopg', 'instrument_django', 'instrument_flask', 'instrument_starlette', 'instrument_aiohttp_client', 'instrument_sqlalchemy', 'instrument_sqlite3', 'instrument_aws_lambda', 'instrument_redis', 'instrument_pymongo', 'instrument_mysql', 'instrument_system_metrics', 'AutoTraceModule', 'with_tags', 'with_settings', 'suppress_scopes', 'shutdown', 'no_auto_trace', 'ScrubMatch', 'ScrubbingOptions', 'VERSION', 'add_non_user_code_prefix', 'suppress_instrumentation', 'StructlogProcessor', 'LogfireLoggingHandler', 'loguru_handler', 'SamplingOptions', 'MetricsOptions']
__all__ = ['Logfire', 'LogfireSpan', 'LevelName', 'AdvancedOptions', 'ConsoleOptions', 'CodeSource', 'PydanticPlugin', 'configure', 'span', 'instrument', 'log', 'trace', 'debug', 'notice', 'info', 'warn', 'warning', 'error', 'exception', 'fatal', 'force_flush', 'log_slow_async_callbacks', 'install_auto_tracing', 'instrument_asgi', 'instrument_wsgi', 'instrument_pydantic', 'instrument_fastapi', 'instrument_openai', 'instrument_anthropic', 'instrument_asyncpg', 'instrument_httpx', 'instrument_celery', 'instrument_requests', 'instrument_psycopg', 'instrument_django', 'instrument_flask', 'instrument_starlette', 'instrument_aiohttp_client', 'instrument_sqlalchemy', 'instrument_sqlite3', 'instrument_aws_lambda', 'instrument_redis', 'instrument_pymongo', 'instrument_mysql', 'instrument_system_metrics', 'AutoTraceModule', 'with_tags', 'with_settings', 'suppress_scopes', 'shutdown', 'no_auto_trace', 'ScrubMatch', 'ScrubbingOptions', 'VERSION', 'add_non_user_code_prefix', 'suppress_instrumentation', 'StructlogProcessor', 'LogfireLoggingHandler', 'loguru_handler', 'SamplingOptions', 'MetricsOptions', 'logfire_info']

DEFAULT_LOGFIRE_INSTANCE = Logfire()
span = DEFAULT_LOGFIRE_INSTANCE.span
Expand Down
43 changes: 2 additions & 41 deletions logfire-api/logfire_api/_internal/cli.pyi
Original file line number Diff line number Diff line change
@@ -1,48 +1,9 @@
import argparse
from ..version import VERSION as VERSION
from .auth import DEFAULT_FILE as DEFAULT_FILE, DefaultFile as DefaultFile, HOME_LOGFIRE as HOME_LOGFIRE, is_logged_in as is_logged_in, poll_for_token as poll_for_token, request_device_code as request_device_code
from .config import LogfireCredentials as LogfireCredentials
from .config_params import ParamManager as ParamManager
from .constants import LOGFIRE_BASE_URL as LOGFIRE_BASE_URL
from .tracer import SDKTracerProvider as SDKTracerProvider
from .utils import read_toml_file as read_toml_file
from _typeshed import Incomplete
from logfire.exceptions import LogfireConfigError as LogfireConfigError
from logfire.propagate import ContextCarrier as ContextCarrier, get_context as get_context
from typing import Any, Sequence

BASE_OTEL_INTEGRATION_URL: str
BASE_DOCS_URL: str
INTEGRATIONS_DOCS_URL: Incomplete
LOGFIRE_LOG_FILE: Incomplete
file_handler: Incomplete
logger: Incomplete
__all__ = ['main', 'logfire_info']

def version_callback() -> None:
"""Show the version and exit."""
def parse_whoami(args: argparse.Namespace) -> None:
"""Show user authenticated username and the URL to your Logfire project."""
def parse_clean(args: argparse.Namespace) -> None:
"""Remove the contents of the Logfire data directory."""

STANDARD_LIBRARY_PACKAGES: Incomplete
OTEL_PACKAGES: set[str]
OTEL_PACKAGE_LINK: Incomplete

def parse_inspect(args: argparse.Namespace) -> None:
"""Inspect installed packages and recommend packages that might be useful."""
def parse_auth(args: argparse.Namespace) -> None:
"""Authenticate with Logfire.
This will authenticate your machine with Logfire and store the credentials.
"""
def parse_list_projects(args: argparse.Namespace) -> None:
"""List user projects."""
def parse_create_new_project(args: argparse.Namespace) -> None:
"""Create a new project."""
def parse_use_project(args: argparse.Namespace) -> None:
"""Use an existing project."""
def parse_info(_args: argparse.Namespace) -> None:
def logfire_info() -> str:
"""Show versions of logfire, OS and related packages."""

class SplitArgs(argparse.Action):
Expand Down
2 changes: 1 addition & 1 deletion logfire-api/logfire_api/_internal/config.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ from .metrics import ProxyMeterProvider as ProxyMeterProvider
from .scrubbing import BaseScrubber as BaseScrubber, NOOP_SCRUBBER as NOOP_SCRUBBER, Scrubber as Scrubber, ScrubbingOptions as ScrubbingOptions
from .stack_info import warn_at_user_stacklevel as warn_at_user_stacklevel
from .tracer import OPEN_SPANS as OPEN_SPANS, PendingSpanProcessor as PendingSpanProcessor, ProxyTracerProvider as ProxyTracerProvider
from .utils import SeededRandomIdGenerator as SeededRandomIdGenerator, UnexpectedResponse as UnexpectedResponse, ensure_data_dir_exists as ensure_data_dir_exists, handle_internal_errors as handle_internal_errors, read_toml_file as read_toml_file, suppress_instrumentation as suppress_instrumentation
from .utils import SeededRandomIdGenerator as SeededRandomIdGenerator, UnexpectedResponse as UnexpectedResponse, ensure_data_dir_exists as ensure_data_dir_exists, handle_internal_errors as handle_internal_errors, platform_is_emscripten as platform_is_emscripten, read_toml_file as read_toml_file, suppress_instrumentation as suppress_instrumentation
from _typeshed import Incomplete
from dataclasses import dataclass
from logfire.exceptions import LogfireConfigError as LogfireConfigError
Expand Down
2 changes: 1 addition & 1 deletion logfire-api/logfire_api/_internal/exporters/otlp.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import requests
from ..stack_info import STACK_INFO_KEYS as STACK_INFO_KEYS
from ..utils import logger as logger, truncate_string as truncate_string
from ..utils import logger as logger, platform_is_emscripten as platform_is_emscripten, truncate_string as truncate_string
from .wrapper import WrapperSpanExporter as WrapperSpanExporter
from _typeshed import Incomplete
from functools import cached_property
Expand Down
26 changes: 17 additions & 9 deletions logfire-api/logfire_api/_internal/stack_info.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@ from typing import TypedDict

StackInfo = TypedDict('StackInfo', {'code.filepath': str, 'code.lineno': int, 'code.function': str}, total=False)
STACK_INFO_KEYS: Incomplete
SITE_PACKAGES_DIR: Incomplete
PYTHON_LIB_DIR: Incomplete
LOGFIRE_DIR: Incomplete
NON_USER_CODE_PREFIXES: Incomplete
NON_USER_CODE_PREFIXES: tuple[str, ...]

def add_non_user_code_prefix(path: str | Path) -> None:
"""Add a path to the list of prefixes that are considered non-user code.
This prevents the stack info from including frames from the given path.
This is for advanced users and shouldn't often be needed.
By default, the following prefixes are already included:
- The standard library
- site-packages (specifically wherever opentelemetry is installed)
- The logfire package
This function is useful if you're writing a library that uses logfire and you want to exclude your library's frames.
Since site-packages is already included, this is already the case by default for users of your library.
But this is useful when testing your library since it's not installed in site-packages.
"""
def get_filepath_attribute(file: str) -> StackInfo: ...
def get_code_object_info(code: CodeType) -> StackInfo: ...
def get_stack_info_from_frame(frame: FrameType) -> StackInfo: ...
Expand Down Expand Up @@ -40,8 +53,3 @@ def is_user_code(code: CodeType) -> bool:
On the other hand, generator expressions and lambdas might be called far away from where they are defined.
"""
def warn_at_user_stacklevel(msg: str, category: type[Warning]): ...
def add_non_user_code_prefix(path: str | Path) -> None:
"""Add a path to the list of prefixes that are considered non-user code.
This prevents the stack info from including frames from the given path.
"""
6 changes: 6 additions & 0 deletions logfire-api/logfire_api/_internal/utils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,9 @@ class SeededRandomIdGenerator(IdGenerator):
def __post_init__(self) -> None: ...
def generate_span_id(self) -> int: ...
def generate_trace_id(self) -> int: ...

def platform_is_emscripten() -> bool:
"""Return True if the platform is Emscripten, e.g. Pyodide.
Threads cannot be created on Emscripten, so we need to avoid any code that creates threads.
"""
2 changes: 2 additions & 0 deletions logfire/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from ._internal.auto_trace import AutoTraceModule
from ._internal.auto_trace.rewrite_ast import no_auto_trace
from ._internal.cli import logfire_info
from ._internal.config import AdvancedOptions, CodeSource, ConsoleOptions, MetricsOptions, PydanticPlugin, configure
from ._internal.constants import LevelName
from ._internal.main import Logfire, LogfireSpan
Expand Down Expand Up @@ -150,4 +151,5 @@ def loguru_handler() -> Any:
'loguru_handler',
'SamplingOptions',
'MetricsOptions',
'logfire_info',
)
10 changes: 8 additions & 2 deletions logfire/_internal/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
logging.basicConfig(handlers=[file_handler], level=logging.DEBUG)

logger = logging.getLogger(__name__)
__all__ = 'main', 'logfire_info'


def version_callback() -> None:
Expand Down Expand Up @@ -318,7 +319,7 @@ def parse_use_project(args: argparse.Namespace) -> None:
)


def parse_info(_args: argparse.Namespace) -> None:
def logfire_info() -> str:
"""Show versions of logfire, OS and related packages."""
import importlib.metadata as importlib_metadata

Expand Down Expand Up @@ -363,7 +364,12 @@ def parse_info(_args: argparse.Namespace) -> None:
'[related_packages]',
*(f'{name}="{version}"' for _, name, version in sorted(related_packages)),
)
sys.stderr.writelines('\n'.join(toml_lines) + '\n')
return '\n'.join(toml_lines) + '\n'


def parse_info(_args: argparse.Namespace) -> None:
"""Show versions of logfire, OS and related packages."""
sys.stderr.writelines(logfire_info())


def _pretty_table(header: list[str], rows: list[list[str]]):
Expand Down
4 changes: 4 additions & 0 deletions tests/test_logfire_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ def func() -> None: ...
logfire_api.MetricsOptions()
logfire__all__.remove('MetricsOptions')

assert hasattr(logfire_api, 'logfire_info')
logfire_api.logfire_info()
logfire__all__.remove('logfire_info')

# If it's not empty, it means that some of the __all__ members are not tested.
assert logfire__all__ == set(), logfire__all__

Expand Down

0 comments on commit 9a51e15

Please sign in to comment.