Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,16 @@ Nelm has powerful resource tracking built from the ground up, much more advanced

![tracking](resources/images/nelm-release-install.gif)

The width of the tracking table adapts to the terminal width automatically. To override it, set `NELM_LOG_TERMINAL_WIDTH` or use `--progress-table-width`:

```shell
# Set a fixed width globally via env var (affects all log output)
NELM_LOG_TERMINAL_WIDTH=200 nelm release install -n myproject -r myproject

# Set a fixed width just for the progress/log/event tables
nelm release install -n myproject -r myproject --progress-table-width 120
```

### Printing logs and events during deploy

During the deployment, Nelm finds Pods of deploying resources and periodically prints their container logs. With annotation `werf.io/show-service-messages: "true"`, resource events are also printed. Can be configured with CLI flags and annotations.
Expand Down
7 changes: 7 additions & 0 deletions cmd/nelm/common_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,13 @@ func AddTrackingFlags(cmd *cobra.Command, cfg *common.TrackingOptions) error {
return fmt.Errorf("add flag: %w", err)
}

if err := cli.AddFlag(cmd, &cfg.ProgressTableWidth, "progress-table-width", 0, "Maximum width in characters for progress, log and event tables. Use 0 for auto-detect from terminal width", cli.AddFlagOptions{
GetEnvVarRegexesFunc: cli.GetFlagGlobalAndLocalEnvVarRegexes,
Group: progressFlagGroup,
}); err != nil {
return fmt.Errorf("add flag: %w", err)
}

return nil
}

Expand Down
3 changes: 2 additions & 1 deletion cmd/nelm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ func main() {
return fg.EnvVarName()
})

if unsupportedEnvVars := lo.Without(cli.FindUndefinedFlagEnvVarsInEnviron(), featGatesEnvVars...); len(unsupportedEnvVars) > 0 {
knownEnvVars := append(featGatesEnvVars, log.LogTerminalWidthEnvVarName)
if unsupportedEnvVars := lo.Without(cli.FindUndefinedFlagEnvVarsInEnviron(), knownEnvVars...); len(unsupportedEnvVars) > 0 {
log.Default.Warn(ctx, "Unsupported environment variable(s): %s", strings.Join(unsupportedEnvVars, ","))
}

Expand Down
Binary file added nelm
Binary file not shown.
1 change: 1 addition & 0 deletions pkg/action/release_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ func releaseInstall(ctx context.Context, ctxCancelFn context.CancelCauseFunc, re
if !opts.NoProgressTablePrint {
progressPrinter = track.NewProgressTablesPrinter(taskStore, logStore, track.ProgressTablesPrinterOptions{
DefaultNamespace: releaseNamespace,
MaxTableWidth: opts.ProgressTableWidth,
})
progressPrinter.Start(ctx, opts.ProgressTablePrintInterval)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/action/release_rollback.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ func releaseRollback(ctx context.Context, ctxCancelFn context.CancelCauseFunc, r
if !opts.NoProgressTablePrint {
progressPrinter = track.NewProgressTablesPrinter(taskStore, logStore, track.ProgressTablesPrinterOptions{
DefaultNamespace: releaseNamespace,
MaxTableWidth: opts.ProgressTableWidth,
})
progressPrinter.Start(ctx, opts.ProgressTablePrintInterval)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/action/release_uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ func releaseUninstall(ctx context.Context, ctxCancelFn context.CancelCauseFunc,
if !opts.NoProgressTablePrint {
progressPrinter = track.NewProgressTablesPrinter(taskStore, logStore, track.ProgressTablesPrinterOptions{
DefaultNamespace: releaseNamespace,
MaxTableWidth: opts.ProgressTableWidth,
})
progressPrinter.Start(ctx, opts.ProgressTablePrintInterval)
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/common/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ type TrackingOptions struct {
// ProgressTablePrintInterval is the interval for updating the progress table display.
// Defaults to DefaultProgressPrintInterval (5 seconds) if not set or <= 0.
ProgressTablePrintInterval time.Duration
// ProgressTableWidth sets a fixed maximum width in characters for progress, log and event tables.
// When 0, the width is auto-detected from the terminal. Defaults to 140 if auto-detection fails.
ProgressTableWidth int
// TrackCreationTimeout is the timeout duration for tracking resource creation.
// If resource creation doesn't complete within this time, the operation fails.
// If 0, no timeout is applied and resources are tracked indefinitely.
Expand Down
9 changes: 9 additions & 0 deletions pkg/log/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
stdlog "log"
"os"
"strconv"

cdlog "github.com/containerd/log"
"github.com/davecgh/go-spew/spew"
Expand All @@ -23,6 +24,8 @@ import (
"github.com/werf/nelm/pkg/helm/pkg/engine"
)

const LogTerminalWidthEnvVarName = "NELM_LOG_TERMINAL_WIDTH"

var Default Logger = NewLogboekLogger()

type SetupLoggingOptions struct {
Expand Down Expand Up @@ -116,6 +119,12 @@ func SetupLogging(ctx context.Context, logLevel Level, opts SetupLoggingOptions)
panic(fmt.Sprintf("unknown log level %q", logLevel))
}

if widthStr := os.Getenv(LogTerminalWidthEnvVarName); widthStr != "" {
if width, err := strconv.Atoi(widthStr); err == nil && width > 0 {
logboek.Context(ctx).Streams().SetWidth(width)
}
}

colorLevel := getColorLevel(opts.ColorMode, opts.LogIsParseable)

color.Enable = colorLevel != terminfo.ColorLevelNone
Expand Down
1 change: 1 addition & 0 deletions pkg/log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Logger interface {
InfoBlock(ctx context.Context, opts BlockOptions, fn func())
InfoBlockErr(ctx context.Context, opts BlockOptions, fn func() error) error
BlockContentWidth(ctx context.Context) int
TerminalWidth(ctx context.Context) int
SetLevel(ctx context.Context, lvl Level)
Level(ctx context.Context) Level
AcceptLevel(ctx context.Context, lvl Level) bool
Expand Down
4 changes: 4 additions & 0 deletions pkg/log/logger_logboek.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ func (l *LogboekLogger) BlockContentWidth(ctx context.Context) int {
return logboek.Context(ctx).Streams().ContentWidth()
}

func (l *LogboekLogger) TerminalWidth(ctx context.Context) int {
return logboek.Context(ctx).Streams().Width()
}

func (l *LogboekLogger) Debug(ctx context.Context, format string, a ...interface{}) {
if !l.AcceptLevel(ctx, DebugLevel) {
return
Expand Down
75 changes: 39 additions & 36 deletions pkg/track/progress_tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,33 +70,38 @@ func (p *ProgressTablesPrinter) Wait() {

type ProgressTablesPrinterOptions struct {
DefaultNamespace string
// MaxTableWidth sets a fixed maximum width in characters for all tables.
// When 0, the width is auto-detected from the terminal.
MaxTableWidth int
}

type tablesBuilder struct {
defaultNamespace string
hideAbsenceTasks map[string]bool
hidePresenceTasks map[string]bool
hideReadinessTasks map[string]bool
logStore *kdutil.Concurrent[*logstore.LogStore]
maxLogEventTableWidth int
maxProgressTableWidth int
nextEventPointers map[string]int
nextLogPointers map[string]int
taskStore *kdutil.Concurrent[*statestore.TaskStore]
configuredMaxTableWidth int
defaultNamespace string
hideAbsenceTasks map[string]bool
hidePresenceTasks map[string]bool
hideReadinessTasks map[string]bool
logStore *kdutil.Concurrent[*logstore.LogStore]
maxLogEventTableWidth int
maxProgressTableWidth int
nextEventPointers map[string]int
nextLogPointers map[string]int
taskStore *kdutil.Concurrent[*statestore.TaskStore]
}

func newTablesBuilder(taskStore *kdutil.Concurrent[*statestore.TaskStore], logStore *kdutil.Concurrent[*logstore.LogStore], opts tablesBuilderOptions) *tablesBuilder {
defaultNamespace := lo.Compact([]string{opts.DefaultNamespace, v1.NamespaceDefault})[0]

builder := &tablesBuilder{
defaultNamespace: defaultNamespace,
hideAbsenceTasks: make(map[string]bool),
hidePresenceTasks: make(map[string]bool),
hideReadinessTasks: make(map[string]bool),
logStore: logStore,
nextEventPointers: make(map[string]int),
nextLogPointers: make(map[string]int),
taskStore: taskStore,
configuredMaxTableWidth: opts.MaxTableWidth,
defaultNamespace: defaultNamespace,
hideAbsenceTasks: make(map[string]bool),
hidePresenceTasks: make(map[string]bool),
hideReadinessTasks: make(map[string]bool),
logStore: logStore,
nextEventPointers: make(map[string]int),
nextLogPointers: make(map[string]int),
taskStore: taskStore,
}

return builder
Expand Down Expand Up @@ -231,23 +236,13 @@ func (b *tablesBuilder) BuildProgressTable() (table prtable.Writer, notEmpty boo
}

func (b *tablesBuilder) SetMaxTableWidth(maxTableWidth int) {
var maxProgressTableWidth int
if maxTableWidth > 0 {
maxProgressTableWidth = maxTableWidth
b.maxProgressTableWidth = maxTableWidth
b.maxLogEventTableWidth = maxTableWidth
} else {
maxProgressTableWidth = 140
b.maxProgressTableWidth = 140
b.maxLogEventTableWidth = 140
}

b.maxProgressTableWidth = lo.Min([]int{maxProgressTableWidth, 200})

var maxLogEventTableWidth int
if maxTableWidth > 0 {
maxLogEventTableWidth = maxTableWidth
} else {
maxLogEventTableWidth = 140
}

b.maxLogEventTableWidth = lo.Min([]int{maxLogEventTableWidth, 250})
}

func (b *tablesBuilder) buildAbsenceProgressRows() (rows []prtable.Row) {
Expand Down Expand Up @@ -422,6 +417,7 @@ func (b *tablesBuilder) buildReadinessProgressRows() (rows []prtable.Row) {

type tablesBuilderOptions struct {
DefaultNamespace string
MaxTableWidth int
}

func buildChildResourceCell(resourceState *statestore.ResourceState) string {
Expand Down Expand Up @@ -745,9 +741,16 @@ func compareKindNameNamespace(iName, iNamespace, iKind, jName, jNamespace, jKind
return false
}

func resolveMaxTableWidth(configuredWidth, autoWidth int) int {
if configuredWidth > 0 {
return min(configuredWidth, autoWidth)
}
return autoWidth
}

func printTables(ctx context.Context, tablesBuilder *tablesBuilder) {
maxTableWidth := log.Default.BlockContentWidth(ctx) - 2
tablesBuilder.SetMaxTableWidth(maxTableWidth)
autoWidth := log.Default.BlockContentWidth(ctx) - 2
tablesBuilder.SetMaxTableWidth(resolveMaxTableWidth(tablesBuilder.configuredMaxTableWidth, autoWidth))

if tables, nonEmpty := tablesBuilder.BuildEventTables(); nonEmpty {
headers := lo.Keys(tables)
Expand Down Expand Up @@ -861,8 +864,8 @@ func setProgressTableStyle(table prtable.Writer, tableWidth int) {
columnsWidth := tableWidth - paddingsWidth

columnConfigs[1].WidthMax = 7
columnConfigs[0].WidthMax = int(float64(columnsWidth-columnConfigs[1].WidthMax) * 0.6)
columnConfigs[2].WidthMax = int(float64(columnsWidth-columnConfigs[1].WidthMax) * 0.4)
columnConfigs[0].WidthMax = int(float64(columnsWidth-columnConfigs[1].WidthMax) * 0.25)
columnConfigs[2].WidthMax = columnsWidth - columnConfigs[1].WidthMax - columnConfigs[0].WidthMax

table.SetColumnConfigs(columnConfigs)
table.SetStyle(prtable.Style{
Expand Down
Loading