Skip to content

Commit 1128f20

Browse files
mirkoCrobumirkoCrobu
authored andcommitted
feat: base structure for log level cmd
1 parent f36d94e commit 1128f20

File tree

5 files changed

+143
-52
lines changed

5 files changed

+143
-52
lines changed

cmd/arduino-app-cli/app/start.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package app
22

33
import (
44
"context"
5-
"fmt"
65

76
"github.com/spf13/cobra"
87

@@ -34,7 +33,6 @@ func newStartCmd() *cobra.Command {
3433
}
3534

3635
func startHandler(ctx context.Context, app app.ArduinoApp) error {
37-
out, _, getResult := feedback.OutputStreams()
3836

3937
stream := orchestrator.StartApp(
4038
ctx,
@@ -47,19 +45,21 @@ func startHandler(ctx context.Context, app app.ArduinoApp) error {
4745
for message := range stream {
4846
switch message.GetType() {
4947
case orchestrator.ProgressType:
50-
fmt.Fprintf(out, "Progress: %.0f%%\n", message.GetProgress().Progress)
48+
feedback.Progress(message.GetProgress().Progress)
5149
case orchestrator.InfoType:
52-
fmt.Fprintln(out, "[INFO]", message.GetData())
50+
feedback.Info(message.GetData())
51+
case orchestrator.DebugType:
52+
feedback.Debug(message.GetData())
53+
case orchestrator.WarningType:
54+
feedback.Warning(message.GetData())
5355
case orchestrator.ErrorType:
5456
feedback.Fatal(message.GetError().Error(), feedback.ErrGeneric)
5557
return nil
5658
}
5759
}
58-
outputResult := getResult()
5960
feedback.PrintResult(results.StartAppResult{
6061
AppName: app.Name,
6162
Status: "started",
62-
Output: outputResult,
6363
})
6464

6565
return nil

cmd/arduino-app-cli/main.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package main
22

33
import (
4-
"cmp"
54
"context"
65
"fmt"
76
"log/slog"
8-
"os"
7+
"strings"
98

109
"github.com/spf13/cobra"
1110
"go.bug.st/cleanup"
@@ -27,31 +26,37 @@ import (
2726
// Version will be set a build time with -ldflags
2827
var Version string = "0.0.0-dev"
2928
var format string
29+
var logLevel string
3030

3131
func run() error {
3232
defer func() { _ = servicelocator.CloseDockerClient() }()
3333

34-
logLevel, err := ParseLogLevel(cmp.Or(os.Getenv("ARDUINO_APP_CLI__LOG_LEVEL"), "INFO"))
35-
if err != nil {
36-
return err
37-
}
38-
slog.SetLogLoggerLevel(logLevel)
39-
4034
rootCmd := &cobra.Command{
4135
Use: "arduino-app-cli",
4236
Short: "A CLI to manage the Python app",
4337
PersistentPreRun: func(cmd *cobra.Command, args []string) {
38+
39+
level, ok := feedback.ParseLogLevel(logLevel)
40+
if !ok {
41+
feedback.Fatal(i18n.Tr("Invalid log level : %s", logLevel), feedback.ErrBadArgument)
42+
}
43+
feedback.SetLogLevel(level)
44+
4445
format, ok := feedback.ParseOutputFormat(format)
4546
if !ok {
4647
feedback.Fatal(i18n.Tr("Invalid output format: %s", format), feedback.ErrBadArgument)
4748
}
4849
feedback.SetFormat(format)
50+
51+
ConfigureSLogger(logLevel)
52+
4953
},
5054
SilenceUsage: true,
5155
SilenceErrors: true,
5256
}
5357

5458
rootCmd.PersistentFlags().StringVar(&format, "format", "text", "Output format (text, json)")
59+
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Set log level (quiet, info, debug/verbose)")
5560

5661
rootCmd.AddCommand(
5762
app.NewAppCmd(),
@@ -88,3 +93,17 @@ func ParseLogLevel(level string) (slog.Level, error) {
8893
}
8994
return l, nil
9095
}
96+
97+
func ConfigureSLogger(levelStr string) {
98+
var slogLevel slog.Level
99+
100+
switch strings.ToLower(levelStr) {
101+
case "quiet":
102+
slogLevel = slog.LevelError
103+
case "debug", "verbose":
104+
slogLevel = slog.LevelDebug
105+
default:
106+
slogLevel = slog.LevelInfo
107+
}
108+
slog.SetLogLoggerLevel(slogLevel)
109+
}

cmd/arduino-app-cli/results/app_results.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,8 @@ func (r CreateAppResult) Data() interface{} {
8787
}
8888

8989
type StartAppResult struct {
90-
AppName string `json:"appName"`
91-
Status string `json:"status"`
92-
Output *feedback.OutputStreamsResult `json:"output,omitempty"`
90+
AppName string `json:"appName"`
91+
Status string `json:"status"`
9392
}
9493

9594
func (r StartAppResult) String() string {

cmd/feedback/feedback.go

Lines changed: 83 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import (
66
"fmt"
77
"io"
88
"os"
9-
10-
"github.com/sirupsen/logrus"
9+
"strings"
1110

1211
"github.com/bcmi-labs/orchestrator/cmd/i18n"
1312
)
@@ -138,16 +137,6 @@ func Print(v string) {
138137
fmt.Fprintln(feedbackOut, v)
139138
}
140139

141-
// Warning outputs a warning message.
142-
func Warning(msg string) {
143-
if format == Text {
144-
fmt.Fprintln(feedbackErr, msg)
145-
} else {
146-
bufferWarnings = append(bufferWarnings, msg)
147-
}
148-
logrus.Warning(msg)
149-
}
150-
151140
// FatalError outputs the error and exits with status exitCode.
152141
func FatalError(err error, exitCode ExitCode) {
153142
Fatal(err.Error(), exitCode)
@@ -241,3 +230,85 @@ func PrintResult(res Result) {
241230
fmt.Fprintln(stdErr, dataErr)
242231
}
243232
}
233+
234+
type LogLevel int
235+
236+
const (
237+
LogLevelQuiet LogLevel = iota
238+
LogLevelInfo
239+
LogLevelDebug
240+
)
241+
242+
var logLevel LogLevel = LogLevelInfo
243+
244+
func SetLogLevel(level LogLevel) {
245+
logLevel = level
246+
}
247+
248+
func ParseLogLevel(levelStr string) (LogLevel, bool) {
249+
switch strings.ToLower(levelStr) {
250+
case "quiet":
251+
return LogLevelQuiet, true
252+
case "info":
253+
return LogLevelInfo, true
254+
case "debug", "verbose":
255+
return LogLevelDebug, true
256+
}
257+
return LogLevelInfo, false
258+
}
259+
260+
func Info(message string) {
261+
if logLevel < LogLevelInfo {
262+
return
263+
}
264+
printLogMessage("[INFO]", message)
265+
}
266+
267+
func Debug(message string) {
268+
if logLevel < LogLevelDebug {
269+
return
270+
}
271+
printLogMessage("[DEBUG]", message)
272+
}
273+
274+
func Warning(message string) {
275+
if logLevel < LogLevelInfo {
276+
return
277+
}
278+
printLogMessage("[WARNING]", message)
279+
}
280+
281+
func printLogMessage(level string, message string) {
282+
switch format {
283+
case JSON, MinifiedJSON:
284+
type logMsg struct {
285+
Level string `json:"level"`
286+
Message string `json:"message"`
287+
}
288+
output, _ := json.Marshal(logMsg{Level: level, Message: message})
289+
fmt.Fprintln(feedbackOut, string(output))
290+
default: // Text
291+
fmt.Fprintf(feedbackErr, "%s %s\n", level, message)
292+
}
293+
}
294+
295+
func Progress(percent float32) {
296+
if logLevel < LogLevelInfo {
297+
return
298+
}
299+
switch format {
300+
case JSON, MinifiedJSON:
301+
type progressMsg struct {
302+
Type string `json:"type"`
303+
Value float32 `json:"value"`
304+
}
305+
output, _ := json.Marshal(progressMsg{Type: "progress", Value: percent})
306+
fmt.Fprintln(feedbackOut, string(output))
307+
default: // Text
308+
309+
fmt.Fprintf(feedbackErr, "\rProgress: %.0f%%", percent*100)
310+
if percent >= 1.0 {
311+
fmt.Fprintln(feedbackErr)
312+
}
313+
}
314+
}

internal/orchestrator/orchestrator.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,13 @@ const (
6767
UnknownType MessageType = ""
6868
ProgressType MessageType = "progress"
6969
InfoType MessageType = "info"
70+
DebugType MessageType = "debug"
71+
WarningType MessageType = "warning"
7072
ErrorType MessageType = "error"
7173
)
7274

7375
type StreamMessage struct {
76+
Type MessageType
7477
data string
7578
error error
7679
progress *Progress
@@ -81,74 +84,73 @@ type Progress struct {
8184
Progress float32
8285
}
8386

84-
func (p *StreamMessage) IsData() bool { return p.data != "" }
87+
func (p *StreamMessage) IsInfo() bool { return p.Type == InfoType }
88+
func (p *StreamMessage) IsDebug() bool { return p.Type == DebugType }
89+
func (p *StreamMessage) IsWarning() bool { return p.Type == WarningType }
8590
func (p *StreamMessage) IsError() bool { return p.error != nil }
8691
func (p *StreamMessage) IsProgress() bool { return p.progress != nil }
8792
func (p *StreamMessage) GetData() string { return p.data }
8893
func (p *StreamMessage) GetError() error { return p.error }
8994
func (p *StreamMessage) GetProgress() *Progress { return p.progress }
9095
func (p *StreamMessage) GetType() MessageType {
91-
if p.IsData() {
92-
return InfoType
93-
}
94-
if p.IsError() {
95-
return ErrorType
96-
}
97-
if p.IsProgress() {
98-
return ProgressType
99-
}
100-
return UnknownType
96+
return p.Type
10197
}
10298

10399
func StartApp(ctx context.Context, docker *dockerClient.Client, provisioner *Provision, modelsIndex *modelsindex.ModelsIndex, bricksIndex *bricksindex.BricksIndex, app app.ArduinoApp) iter.Seq[StreamMessage] {
104100
return func(yield func(StreamMessage) bool) {
105101
ctx, cancel := context.WithCancel(ctx)
106102
defer cancel()
107103

104+
if !yield(StreamMessage{Type: DebugType, data: "Checking for already running apps..."}) {
105+
cancel()
106+
return
107+
}
108108
running, err := getRunningApp(ctx, docker)
109109
if err != nil {
110-
yield(StreamMessage{error: err})
110+
yield(StreamMessage{Type: ErrorType, error: err})
111111
return
112112
}
113113
if running != nil {
114-
yield(StreamMessage{error: fmt.Errorf("app %q is running", running.Name)})
114+
err := fmt.Errorf("app %q is already running", running.Name)
115+
yield(StreamMessage{Type: ErrorType, error: err})
115116
return
116117
}
117118

118119
callbackWriter := NewCallbackWriter(func(line string) {
119-
if !yield(StreamMessage{data: line}) {
120+
if !yield(StreamMessage{Type: DebugType, data: line}) {
120121
cancel()
121122
return
122123
}
123124
})
124125

125126
if app.MainSketchPath != nil {
126-
if !yield(StreamMessage{data: "compiling and updating sketch..."}) {
127+
if !yield(StreamMessage{Type: InfoType, data: "Compiling and updating sketch..."}) {
127128
cancel()
128129
return
129130
}
130131
if err := compileUploadSketch(ctx, &app, callbackWriter); err != nil {
131-
yield(StreamMessage{error: err})
132+
yield(StreamMessage{Type: ErrorType, error: err})
132133
return
133134
}
134135
}
135136
if app.MainPythonFile != nil {
136-
if !yield(StreamMessage{data: "Provisioning app..."}) {
137+
if !yield(StreamMessage{Type: InfoType, data: "Provisioning app..."}) {
137138
cancel()
138139
return
139140
}
140141
if err := ProvisionApp(ctx, provisioner, bricksIndex, &app); err != nil {
141-
yield(StreamMessage{error: err})
142+
yield(StreamMessage{Type: ErrorType, error: err})
142143
return
143144
}
144-
if !yield(StreamMessage{data: "Starting app..."}) {
145+
146+
if !yield(StreamMessage{Type: InfoType, data: "Starting app..."}) {
145147
cancel()
146148
return
147149
}
148150

149151
provisioningStateDir, err := getProvisioningStateDir(app)
150152
if err != nil {
151-
yield(StreamMessage{error: err})
153+
yield(StreamMessage{Type: ErrorType, error: err})
152154
return
153155
}
154156

@@ -176,17 +178,17 @@ func StartApp(ctx context.Context, docker *dockerClient.Client, provisioner *Pro
176178
commands = append(commands, "up", "-d", "--remove-orphans", "--pull", "missing")
177179
process, err := paths.NewProcess(envs, commands...)
178180
if err != nil {
179-
yield(StreamMessage{error: err})
181+
yield(StreamMessage{Type: ErrorType, error: err})
180182
return
181183
}
182184
process.RedirectStderrTo(callbackWriter)
183185
process.RedirectStdoutTo(callbackWriter)
184186
if err := process.RunWithinContext(ctx); err != nil {
185-
yield(StreamMessage{error: err})
187+
yield(StreamMessage{Type: ErrorType, error: err})
186188
return
187189
}
188190
}
189-
_ = yield(StreamMessage{progress: &Progress{Name: "", Progress: 100.0}})
191+
_ = yield(StreamMessage{Type: ProgressType, progress: &Progress{Name: "", Progress: 100.0}})
190192
}
191193
}
192194

0 commit comments

Comments
 (0)