feat: container logs viewer with SSE streaming and line limiter

- Add GET /api/projects/{id}/stages/{stage}/instances/{iid}/logs endpoint
- Supports JSON mode (returns array of lines) and SSE mode (streams in real-time)
- Docker log stream header (8-byte prefix) stripped automatically
- ContainerLogs component with:
  - Tail line selector (50/200/500/1000)
  - Follow button for real-time streaming via SSE
  - Auto-scroll to bottom
  - Dark terminal-style display
  - Close button
- Logs button (events icon) on each instance card
- i18n keys in EN and RU
This commit is contained in:
2026-04-05 14:04:45 +03:00
parent ac3132d172
commit d03cc3c811
8 changed files with 322 additions and 1 deletions
+18
View File
@@ -3,6 +3,7 @@ package docker
import (
"context"
"fmt"
"io"
"regexp"
"strconv"
"strings"
@@ -266,6 +267,23 @@ func (c *Client) ListContainers(ctx context.Context, labelFilters map[string]str
return result, nil
}
// ContainerLogs returns a log stream for a container.
// If follow is true, the stream stays open for new log lines.
// tail specifies the number of lines from the end to return (e.g., "200").
func (c *Client) ContainerLogs(ctx context.Context, containerID string, follow bool, tail string) (io.ReadCloser, error) {
result, err := c.api.ContainerLogs(ctx, containerID, client.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
Follow: follow,
Tail: tail,
Timestamps: true,
})
if err != nil {
return nil, fmt.Errorf("container logs %s: %w", containerID, err)
}
return result, nil
}
// IsContainerRunning checks if a container is in the "running" state.
func (c *Client) IsContainerRunning(ctx context.Context, containerID string) (bool, error) {
inspectResult, err := c.api.ContainerInspect(ctx, containerID, client.ContainerInspectOptions{})