Skip to content

Tail

provide.foundation.cli.commands.logs.tail

TODO: Add module docstring.

Functions

tail_command

tail_command(
    ctx: Context,
    stream: str,
    filter_str: str | None,
    lines: int,
    follow: bool,
    format: str,
) -> int | None

Tail logs in real-time (like 'tail -f').

Examples:

Tail all logs

foundation logs tail

Tail error logs only

foundation logs tail --filter "level='ERROR'"

Tail specific service

foundation logs tail --filter "service='auth-service'"

Show last 20 lines and exit

foundation logs tail -n 20 --no-follow

Tail with JSON output

foundation logs tail --format json

Source code in provide/foundation/cli/commands/logs/tail.py
@click.command("tail")
@click.option(
    "--stream",
    "-s",
    default="default",
    help="Stream to tail",
)
@click.option(
    "--filter",
    "-f",
    "filter_str",
    help="Filter logs using key='value' pairs (e.g., \"level='ERROR', service='api'\")",
)
@click.option(
    "--lines",
    "-n",
    type=int,
    default=10,
    help="Number of initial lines to show",
)
@click.option(
    "--follow/--no-follow",
    "-F/-N",
    default=True,
    help="Follow mode (like tail -f)",
)
@click.option(
    "--format",
    type=click.Choice(["log", "json"]),
    default="log",
    help="Output format",
)
@click.pass_context
@requires_click
@with_cleanup
def tail_command(
    ctx: click.Context,
    stream: str,
    filter_str: str | None,
    lines: int,
    follow: bool,
    format: str,
) -> int | None:
    """Tail logs in real-time (like 'tail -f').

    Examples:
        # Tail all logs
        foundation logs tail

        # Tail error logs only
        foundation logs tail --filter "level='ERROR'"

        # Tail specific service
        foundation logs tail --filter "service='auth-service'"

        # Show last 20 lines and exit
        foundation logs tail -n 20 --no-follow

        # Tail with JSON output
        foundation logs tail --format json

    """
    from provide.foundation.integrations.openobserve import (
        format_output,
        tail_logs,
    )

    # Get client from context
    client, error_code = get_client_from_context(ctx)
    if error_code != 0:
        exit_error("OpenObserve client not configured", code=error_code)

    try:
        filters = _parse_filter_string_for_tail(filter_str)

        click.echo(f"📡 Tailing logs from stream '{stream}'...")
        if filters:
            click.echo(f"   Filter: {filters}")
        click.echo("   Press Ctrl+C to stop\n")

        # Tail logs
        for log_entry in tail_logs(
            stream=stream,
            filters=filters,
            follow=follow,
            lines=lines,
            client=client,
        ):
            output = format_output(log_entry, format_type=format)
            click.echo(output)

    except KeyboardInterrupt:
        click.echo("\n✋ Stopped tailing logs.")
    except Exception as e:
        click.echo(f"Tail failed: {e}", err=True)
        exit_error("Tail command failed", code=1)

    return None