Skip to content

Commit

Permalink
feat: improve status colors (#2817)
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartwdouglas authored Sep 25, 2024
1 parent 431a19e commit 57eea5b
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 42 deletions.
4 changes: 2 additions & 2 deletions backend/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,7 @@ func (s *Service) executeAsyncCalls(ctx context.Context) (interval time.Duration
call.Release() //nolint:errcheck
}()

logger = logger.Scope(fmt.Sprintf("%s:%s", call.Origin, call.Verb))
logger = logger.Scope(fmt.Sprintf("%s:%s", call.Origin, call.Verb)).Module(call.Verb.Module)

if call.Catching {
// Retries have been exhausted but catch verb has previously failed
Expand Down Expand Up @@ -1516,7 +1516,7 @@ func (s *Service) finaliseAsyncCall(ctx context.Context, tx *dal.DAL, call *dal.
}

func (s *Service) onAsyncFSMCallCompletion(ctx context.Context, tx *dal.DAL, origin async.AsyncOriginFSM, failed bool, isFinalResult bool) error {
logger := log.FromContext(ctx).Scope(origin.FSM.String())
logger := log.FromContext(ctx).Scope(origin.FSM.String()).Module(origin.FSM.Module)

// retrieve the next fsm event and delete it
next, err := tx.PopNextFSMEvent(ctx, origin.FSM, origin.Key)
Expand Down
4 changes: 2 additions & 2 deletions backend/controller/cronjobs/cronjobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func NewForTesting(ctx context.Context, key model.ControllerKey, requestSource s
}

func (s *Service) NewCronJobsForModule(ctx context.Context, module *schemapb.Module) ([]model.CronJob, error) {
logger := log.FromContext(ctx).Scope("cron")
logger := log.FromContext(ctx).Scope("cron").Module(module.Name)
start := s.clock.Now().UTC()
newJobs := []model.CronJob{}
merr := []error{}
Expand Down Expand Up @@ -149,7 +149,7 @@ func (s *Service) OnJobCompletion(ctx context.Context, key model.CronJobKey, fai

// scheduleCronJob schedules the next execution of a single cron job.
func (s *Service) scheduleCronJob(ctx context.Context, tx *dal.DAL, job model.CronJob) error {
logger := log.FromContext(ctx).Scope("cron")
logger := log.FromContext(ctx).Scope("cron").Module(job.Verb.Module)
now := s.clock.Now().UTC()
pending, err := tx.IsCronJobPending(ctx, job.Key, now)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions backend/controller/ingress/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func Handle(
observability.Ingress.Request(r.Context(), r.Method, r.URL.Path, optional.None[*schemapb.Ref](), startTime, optional.Some("failed to resolve route"))
return
}
logger = logger.Module(route.Module)

verbRef := &schemapb.Ref{Module: route.Module, Name: route.Verb}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ func (r *DeploymentProvisioner) handleSchemaChange(ctx context.Context, msg *ftl
return nil
}
logger := log.FromContext(ctx)
logger = logger.Module(msg.ModuleName)
ctx = log.ContextWithLogger(ctx, logger)
logger.Infof("Handling schema change for %s", msg.DeploymentKey)
deploymentClient := r.Client.AppsV1().Deployments(r.Namespace)
deployment, err := deploymentClient.Get(ctx, msg.DeploymentKey, v1.GetOptions{})
Expand Down
4 changes: 2 additions & 2 deletions backend/controller/scaling/localscaling/local_scaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (l *localScaling) handleSchemaChange(ctx context.Context, msg *ftlv1.PullSc
}
l.lock.Lock()
defer l.lock.Unlock()
logger := log.FromContext(ctx).Scope("localScaling")
logger := log.FromContext(ctx).Scope("localScaling").Module(msg.ModuleName)
ctx = log.ContextWithLogger(ctx, logger)
logger.Infof("Handling schema change for %s", msg.DeploymentKey)
moduleDeployments := l.runners[msg.ModuleName]
Expand Down Expand Up @@ -192,7 +192,7 @@ func (l *localScaling) startRunner(ctx context.Context, deploymentKey string, in
config.HeartbeatPeriod = time.Second
config.HeartbeatJitter = time.Millisecond * 100

runnerCtx := log.ContextWithLogger(ctx, logger.Scope(simpleName))
runnerCtx := log.ContextWithLogger(ctx, logger.Scope(simpleName).Module(info.module))

runnerCtx, cancel := context.WithCancel(runnerCtx)
info.runner = optional.Some(runnerInfo{cancelFunc: cancel, port: bind.Port()})
Expand Down
2 changes: 1 addition & 1 deletion frontend/cli/cmd_interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type interactiveCmd struct {
}

func (i *interactiveCmd) Run(ctx context.Context, k *kong.Kong, projectConfig projectconfig.Config, binder terminal.KongContextBinder, cancel context.CancelFunc, client ftlv1connect.ControllerServiceClient) error {
err := terminal.RunInteractiveConsole(ctx, k, projectConfig, binder, nil, cancel, client)
err := terminal.RunInteractiveConsole(ctx, k, projectConfig, binder, cancel, client)
if err != nil {
return fmt.Errorf("interactive console: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/buildengine/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func buildModule(ctx context.Context, projectRootDir string, sch *schema.Schema,
return err
}
defer release() //nolint:errcheck
logger := log.FromContext(ctx).Scope(module.Config.Module)
logger := log.FromContext(ctx).Module(module.Config.Module).Scope("build")
ctx = log.ContextWithLogger(ctx, logger)

// clear the deploy directory before extracting schema
Expand Down
4 changes: 2 additions & 2 deletions internal/buildengine/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type DeployClient interface {

// Deploy a module to the FTL controller with the given number of replicas. Optionally wait for the deployment to become ready.
func Deploy(ctx context.Context, module Module, replicas int32, waitForDeployOnline bool, client DeployClient) error {
logger := log.FromContext(ctx).Scope(module.Config.Module)
logger := log.FromContext(ctx).Module(module.Config.Module).Scope("deploy")
ctx = log.ContextWithLogger(ctx, logger)
logger.Infof("Deploying module")

Expand Down Expand Up @@ -107,7 +107,7 @@ func Deploy(ctx context.Context, module Module, replicas int32, waitForDeployOnl
}

func terminateModuleDeployment(ctx context.Context, client ftlv1connect.ControllerServiceClient, module string) error {
logger := log.FromContext(ctx).Scope(module)
logger := log.FromContext(ctx).Module(module).Scope("terminate")

status, err := client.Status(ctx, connect.NewRequest(&ftlv1.StatusRequest{}))
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/buildengine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ func (e *Engine) buildWithCallback(ctx context.Context, callback buildCallback,
wg.SetLimit(e.parallelism)
for _, moduleName := range group {
wg.Go(func() error {
logger := log.FromContext(ctx).Scope(moduleName)
logger := log.FromContext(ctx).Module(moduleName).Scope("build")
ctx := log.ContextWithLogger(ctx, logger)
err := e.tryBuild(ctx, mustBuild, moduleName, builtModules, schemas, callback)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions internal/log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
var _ Interface = (*Logger)(nil)

const scopeKey = "scope"
const moduleKey = "module"

type Entry struct {
Time time.Time `json:"-"`
Expand Down Expand Up @@ -46,6 +47,9 @@ func New(level Level, sink Sink) *Logger {
func (l Logger) Scope(scope string) *Logger {
return l.Attrs(map[string]string{scopeKey: scope})
}
func (l Logger) Module(module string) *Logger {
return l.Attrs(map[string]string{moduleKey: module})
}

// Attrs creates a new logger with the given attributes.
func (l Logger) Attrs(attributes map[string]string) *Logger {
Expand Down
18 changes: 15 additions & 3 deletions internal/log/plain.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,24 @@ func (t *plainSink) Log(entry Entry) error {
}

// Add scope if required
scopeString := ""
scope, exists := entry.Attributes[scopeKey]
module, moduleExists := entry.Attributes[moduleKey]
if moduleExists {
if exists && scope != module {
scopeString = module + ":" + scope
} else {
scopeString = module
}
} else if exists {
scopeString = scope
module = scope
}
if exists {
if t.isaTTY {
prefix += entry.Level.String() + ":" + scopeColour(scope) + scope + "\x1b[0m: "
prefix += entry.Level.String() + ":" + ScopeColor(module) + scopeString + "\x1b[0m: "
} else {
prefix += entry.Level.String() + ":" + scope + ": "
prefix += entry.Level.String() + ":" + scopeString + ": "
}
} else {
prefix += entry.Level.String() + ": "
Expand All @@ -128,7 +140,7 @@ func parseRGB(s string) (int, int, int) {
return int(r), int(g), int(b)
}

func scopeColour(scope string) string {
func ScopeColor(scope string) string {
hash := fnv.New32a()
hash.Write([]byte(scope))
colours, _ := scopeColours.Get(context.Background()) //nolint:errcheck
Expand Down
23 changes: 17 additions & 6 deletions internal/terminal/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,32 @@ import (
"github.com/TBD54566975/ftl/internal/projectconfig"
)

const interactivePrompt = "\033[32m>\033[0m "

var _ readline.AutoCompleter = &FTLCompletion{}
var errExitTrap = errors.New("exit trap")

type KongContextBinder func(ctx context.Context, kctx *kong.Context, projectConfig projectconfig.Config, app *kong.Kong, cancel context.CancelFunc) context.Context

func RunInteractiveConsole(ctx context.Context, k *kong.Kong, projectConfig projectconfig.Config, binder KongContextBinder, refreshFunction func(func()), cancelContext context.CancelFunc, client ftlv1connect.ControllerServiceClient) error {
func RunInteractiveConsole(ctx context.Context, k *kong.Kong, projectConfig projectconfig.Config, binder KongContextBinder, cancelContext context.CancelFunc, client ftlv1connect.ControllerServiceClient) error {

l, err := readline.NewEx(&readline.Config{
Prompt: "\033[32m>\033[0m ",
Prompt: interactivePrompt,
InterruptPrompt: "^C",
AutoComplete: &FTLCompletion{app: k, ctx: ctx, client: client},
Listener: &ExitListener{cancel: func() {
os.Exit(0)
}},
})
if refreshFunction != nil {
refreshFunction(l.Refresh)
sm := FromContext(ctx)
var tsm *terminalStatusManager
ok := false
if tsm, ok = sm.(*terminalStatusManager); ok {
tsm.statusLock.Lock()
tsm.console = true
tsm.consoleRefresh = l.Refresh
tsm.recalculateLines()
tsm.statusLock.Unlock()
}
if err != nil {
return fmt.Errorf("init readline: %w", err)
Expand All @@ -54,6 +64,9 @@ func RunInteractiveConsole(ctx context.Context, k *kong.Kong, projectConfig proj
} else if errors.Is(err, io.EOF) {
os.Exit(0)
}
if tsm != nil {
tsm.consoleNewline(line)
}
line = strings.TrimSpace(line)
if line == "" {
continue
Expand Down Expand Up @@ -84,8 +97,6 @@ func RunInteractiveConsole(ctx context.Context, k *kong.Kong, projectConfig proj
errorf("error: %s", err)
return
}
// Force a status refresh
println("")
}()
}
return nil
Expand Down
Loading

0 comments on commit 57eea5b

Please sign in to comment.