Skip to content

Commit 0da29da

Browse files
authored
fix: honor LOG_LEVEL env in daemon logger (#686)
1 parent 1ca8931 commit 0da29da

6 files changed

Lines changed: 166 additions & 3 deletions

File tree

cmd/server/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func main() {
2626
}
2727
time.Local = loc
2828

29-
logCloser, err := log.Init(config.LogOutputFormat == "json", config.LogFile)
29+
logCloser, err := log.Init(config.LogOutputFormat == "json", config.LogFile, config.LogLevel)
3030
if err != nil {
3131
log.Panic("failed to init logger", "error", err)
3232
}

internal/types/app/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/go-playground/validator/v10"
1313
gormConfig "github.com/langgenius/dify-plugin-daemon/internal/db/config"
1414
"github.com/langgenius/dify-plugin-daemon/pkg/entities/plugin_entities"
15+
pkglog "github.com/langgenius/dify-plugin-daemon/pkg/utils/log"
1516
)
1617

1718
const (
@@ -248,6 +249,7 @@ type Config struct {
248249

249250
// log settings
250251
HealthApiLogEnabled bool `envconfig:"HEALTH_API_LOG_ENABLED" default:"true"`
252+
LogLevel string `envconfig:"LOG_LEVEL" default:"INFO"`
251253
LogOutputFormat string `envconfig:"LOG_OUTPUT_FORMAT" default:"text"`
252254
LogFile string `envconfig:"LOG_FILE" default:""`
253255

@@ -309,6 +311,9 @@ func (c *Config) Validate() error {
309311
return fmt.Errorf("invalid gorm log level: '%s'. Valid levels are: silent, error, warn, info", c.DBGormLogLevel)
310312
}
311313
}
314+
if _, err := pkglog.ParseLevel(c.LogLevel); err != nil {
315+
return err
316+
}
312317
return nil
313318
}
314319

internal/types/app/config_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,73 @@ import (
1010
"github.com/stretchr/testify/require"
1111
)
1212

13+
func newValidConfigForValidation() *Config {
14+
config := &Config{
15+
ServerPort: 5002,
16+
ServerKey: "test-key",
17+
DifyInnerApiURL: "http://localhost",
18+
DifyInnerApiKey: "test-api-key",
19+
Platform: PLATFORM_LOCAL,
20+
PluginWorkingPath: "plugin-working",
21+
DBType: DB_TYPE_POSTGRESQL,
22+
DBUsername: "postgres",
23+
DBPassword: "postgres",
24+
DBHost: "localhost",
25+
DBPort: 5432,
26+
DBDatabase: "plugin",
27+
}
28+
config.SetDefault()
29+
return config
30+
}
31+
32+
func TestValidateLogLevel(t *testing.T) {
33+
tests := []struct {
34+
name string
35+
logLevel string
36+
expectedErr string
37+
}{
38+
{
39+
name: "empty uses default",
40+
logLevel: "",
41+
},
42+
{
43+
name: "uppercase info",
44+
logLevel: "INFO",
45+
},
46+
{
47+
name: "uppercase warn",
48+
logLevel: "WARN",
49+
},
50+
{
51+
name: "invalid level",
52+
logLevel: "verbose",
53+
expectedErr: `invalid LOG_LEVEL "verbose". Valid values are: DEBUG, INFO, WARN, ERROR`,
54+
},
55+
{
56+
name: "lowercase rejected",
57+
logLevel: "info",
58+
expectedErr: `invalid LOG_LEVEL "info". Valid values are: DEBUG, INFO, WARN, ERROR`,
59+
},
60+
}
61+
62+
for _, tt := range tests {
63+
t.Run(tt.name, func(t *testing.T) {
64+
config := newValidConfigForValidation()
65+
config.LogLevel = tt.logLevel
66+
67+
err := config.Validate()
68+
69+
if tt.expectedErr != "" {
70+
require.Error(t, err)
71+
assert.Equal(t, tt.expectedErr, err.Error())
72+
return
73+
}
74+
75+
require.NoError(t, err)
76+
})
77+
}
78+
}
79+
1380
func TestRedisTLSConfig(t *testing.T) {
1481
tests := []struct {
1582
name string

internal/types/app/default.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func (config *Config) SetDefault() {
3333
setDefaultString(&config.PluginStorageLocalRoot, "storage")
3434
setDefaultString(&config.PluginInstalledPath, "plugin")
3535
setDefaultString(&config.PluginMediaCachePath, "assets")
36+
setDefaultString(&config.LogLevel, "INFO")
3637
setDefaultString(&config.PersistenceStoragePath, "persistence")
3738
setDefaultInt(&config.PluginLocalLaunchingConcurrent, 2)
3839
setDefaultInt(&config.PersistenceStorageMaxSize, 100*1024*1024)

pkg/utils/log/log.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,24 @@ import (
1515

1616
const ServiceName = "dify-plugin-daemon"
1717

18-
func Init(json bool, filename string) (io.Closer, error) {
18+
func ParseLevel(value string) (slog.Level, error) {
19+
switch value {
20+
case "":
21+
return slog.LevelInfo, nil
22+
case "DEBUG":
23+
return slog.LevelDebug, nil
24+
case "INFO":
25+
return slog.LevelInfo, nil
26+
case "WARN":
27+
return slog.LevelWarn, nil
28+
case "ERROR":
29+
return slog.LevelError, nil
30+
default:
31+
return 0, fmt.Errorf("invalid LOG_LEVEL %q. Valid values are: DEBUG, INFO, WARN, ERROR", value)
32+
}
33+
}
34+
35+
func Init(json bool, filename string, level string) (io.Closer, error) {
1936
var w io.Writer = os.Stdout
2037
var closer io.Closer
2138
if filename != "" {
@@ -30,8 +47,17 @@ func Init(json bool, filename string) (io.Closer, error) {
3047
w = io.MultiWriter(os.Stdout, file)
3148
closer = file
3249
}
50+
51+
logLevel, err := ParseLevel(level)
52+
if err != nil {
53+
if closer != nil {
54+
_ = closer.Close()
55+
}
56+
return nil, err
57+
}
58+
3359
handler := NewHandler(Options{
34-
Level: slog.LevelInfo,
60+
Level: logLevel,
3561
Service: ServiceName,
3662
JSON: json,
3763
Out: w,

pkg/utils/log/log_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package log
2+
3+
import (
4+
"log/slog"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestParseLevel(t *testing.T) {
12+
tests := []struct {
13+
name string
14+
value string
15+
expected slog.Level
16+
expectedErr string
17+
}{
18+
{
19+
name: "empty defaults to info",
20+
value: "",
21+
expected: slog.LevelInfo,
22+
},
23+
{
24+
name: "uppercase info",
25+
value: "INFO",
26+
expected: slog.LevelInfo,
27+
},
28+
{
29+
name: "uppercase debug",
30+
value: "DEBUG",
31+
expected: slog.LevelDebug,
32+
},
33+
{
34+
name: "invalid level",
35+
value: "verbose",
36+
expectedErr: `invalid LOG_LEVEL "verbose". Valid values are: DEBUG, INFO, WARN, ERROR`,
37+
},
38+
{
39+
name: "lowercase rejected",
40+
value: "info",
41+
expectedErr: `invalid LOG_LEVEL "info". Valid values are: DEBUG, INFO, WARN, ERROR`,
42+
},
43+
{
44+
name: "warning alias rejected",
45+
value: "WARNING",
46+
expectedErr: `invalid LOG_LEVEL "WARNING". Valid values are: DEBUG, INFO, WARN, ERROR`,
47+
},
48+
}
49+
50+
for _, tt := range tests {
51+
t.Run(tt.name, func(t *testing.T) {
52+
level, err := ParseLevel(tt.value)
53+
54+
if tt.expectedErr != "" {
55+
require.Error(t, err)
56+
assert.Equal(t, tt.expectedErr, err.Error())
57+
return
58+
}
59+
60+
require.NoError(t, err)
61+
assert.Equal(t, tt.expected, level)
62+
})
63+
}
64+
}

0 commit comments

Comments
 (0)