Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:(logging) Added Log Format provision #8890

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
16 changes: 16 additions & 0 deletions go/cmd/dolt/commands/sqlserver/command_line_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type commandLineServerConfig struct {
timeout uint64
readOnly bool
logLevel servercfg.LogLevel
logFormat servercfg.LogFormat
dataDir string
cfgDir string
autoCommit bool
Expand Down Expand Up @@ -68,6 +69,7 @@ func DefaultCommandLineServerConfig() *commandLineServerConfig {
timeout: servercfg.DefaultTimeout,
readOnly: servercfg.DefaultReadOnly,
logLevel: servercfg.DefaultLogLevel,
logFormat: servercfg.DefaultLogFormat,
autoCommit: servercfg.DefaultAutoCommit,
maxConnections: servercfg.DefaultMaxConnections,
dataDir: servercfg.DefaultDataDir,
Expand Down Expand Up @@ -143,6 +145,9 @@ func NewCommandLineConfig(creds *cli.UserPassword, apr *argparser.ArgParseResult
if logLevel, ok := apr.GetValue(logLevelFlag); ok {
config.withLogLevel(servercfg.LogLevel(strings.ToLower(logLevel)))
}
if logFormat, ok := apr.GetValue(logFormatFlag); ok {
config.withLogFormat(servercfg.LogFormat(strings.ToLower(logFormat)))
}

if dataDir, ok := apr.GetValue(commands.MultiDBDirFlag); ok {
config.withDataDir(dataDir)
Expand Down Expand Up @@ -232,6 +237,11 @@ func (cfg *commandLineServerConfig) LogLevel() servercfg.LogLevel {
return cfg.logLevel
}

// LogFormat returns the format of logging that the server will use.
func (cfg *commandLineServerConfig) LogFormat() servercfg.LogFormat {
return cfg.logFormat
}

// AutoCommit defines the value of the @@autocommit session variable used on every connection
func (cfg *commandLineServerConfig) AutoCommit() bool {
return cfg.autoCommit
Expand Down Expand Up @@ -399,6 +409,12 @@ func (cfg *commandLineServerConfig) withLogLevel(loglevel servercfg.LogLevel) *c
cfg.valuesSet[servercfg.LogLevelKey] = struct{}{}
return cfg
}
// withLogFormat updates the log format and returns the called `*commandLineServerConfig`, which is useful for chaining calls.
func (cfg *commandLineServerConfig) withLogFormat(logformat servercfg.LogFormat) *commandLineServerConfig {
cfg.logFormat = logformat
cfg.valuesSet[servercfg.LogFormatKey] = struct{}{}
return cfg
}

// withMaxConnections updates the maximum number of concurrent connections and returns the called
// `*commandLineServerConfig`, which is useful for chaining calls.
Expand Down
7 changes: 7 additions & 0 deletions go/cmd/dolt/commands/sqlserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ func ConfigureServices(
return err
}
logrus.SetLevel(level)
format := strings.ToLower(fmt.Sprintf("%v", serverConfig.LogFormat()))
switch format {
case "json":
logrus.SetFormatter(&logrus.JSONFormatter{})
default:
logrus.SetFormatter(&logrus.TextFormatter{})
}

sql.SystemVariables.AddSystemVariables([]sql.SystemVariable{
&sql.MysqlSystemVariable{
Expand Down
4 changes: 4 additions & 0 deletions go/cmd/dolt/commands/sqlserver/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ func TestServerGoodParams(t *testing.T) {
DefaultCommandLineServerConfig().withLogLevel(servercfg.LogLevel_Info).WithPort(15408),
DefaultCommandLineServerConfig().withReadOnly(true).WithPort(15409),
DefaultCommandLineServerConfig().withUser("testusernamE").withPassword("hunter2").withTimeout(4).WithPort(15410),
DefaultCommandLineServerConfig().withLogFormat(servercfg.LogFormat_Text).WithPort(15411),
DefaultCommandLineServerConfig().withLogFormat(servercfg.LogFormat_JSON).WithPort(15412),
DefaultCommandLineServerConfig().withAllowCleartextPasswords(true),
}

Expand Down Expand Up @@ -552,6 +554,8 @@ func TestGenerateYamlConfig(t *testing.T) {

# log_level: info

# log_format: text

# max_logged_query_len: 0

# encode_logged_query: false
Expand Down
2 changes: 2 additions & 0 deletions go/cmd/dolt/commands/sqlserver/sqlserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
timeoutFlag = "timeout"
readonlyFlag = "readonly"
logLevelFlag = "loglevel"
logFormatFlag = "logformat"
noAutoCommitFlag = "no-auto-commit"
configFileFlag = "config"
queryParallelismFlag = "query-parallelism"
Expand Down Expand Up @@ -167,6 +168,7 @@ func (cmd SqlServerCmd) ArgParserWithName(name string) *argparser.ArgParser {
ap.SupportsInt(timeoutFlag, "t", "connection timeout", fmt.Sprintf("Defines the timeout, in seconds, used for connections\nA value of `0` represents an infinite timeout. Defaults to `%v`.", serverConfig.ReadTimeout()))
ap.SupportsFlag(readonlyFlag, "r", "Disable modification of the database.")
ap.SupportsString(logLevelFlag, "l", "log level", fmt.Sprintf("Defines the level of logging provided\nOptions are: `trace`, `debug`, `info`, `warning`, `error`, `fatal`. Defaults to `%v`.", serverConfig.LogLevel()))
ap.SupportsString(logFormatFlag, "f", "log format", fmt.Sprintf("Defines the level of format provided\nOptions are: `text`, `json`. Defaults to `%v`.", serverConfig.LogFormat()))
ap.SupportsString(commands.DataDirFlag, "", "directory", "Defines a directory to find databases to serve. Defaults to the current directory.")
ap.SupportsString(commands.MultiDBDirFlag, "", "directory", "Deprecated, use `--data-dir` instead.")
ap.SupportsString(commands.CfgDirFlag, "", "directory", "Defines a directory that contains non-database storage for dolt. Defaults to `$data-dir/.doltcfg`. Will be created automatically as needed.")
Expand Down
16 changes: 16 additions & 0 deletions go/libraries/doltcore/servercfg/serverconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ const (
LogLevel_Panic LogLevel = "panic"
)

type LogFormat string

const (
LogFormat_Text LogFormat = "text"
LogFormat_JSON LogFormat = "json"
)

const (
DefaultHost = "localhost"
DefaultPort = 3306
Expand All @@ -47,6 +54,7 @@ const (
DefaultTimeout = 8 * 60 * 60 * 1000 // 8 hours, same as MySQL
DefaultReadOnly = false
DefaultLogLevel = LogLevel_Info
DefaultLogFormat = LogFormat_Text
DefaultAutoCommit = true
DefaultAutoGCBehaviorEnable = false
DefaultDoltTransactionCommit = false
Expand Down Expand Up @@ -138,6 +146,8 @@ type ServerConfig interface {
ReadOnly() bool
// LogLevel returns the level of logging that the server will use.
LogLevel() LogLevel
// LogFormat returns the format of logging that the server will use.
LogFormat() LogFormat
// Autocommit defines the value of the @@autocommit session variable used on every connection
AutoCommit() bool
// DoltTransactionCommit defines the value of the @@dolt_transaction_commit session variable that enables Dolt
Expand Down Expand Up @@ -211,6 +221,7 @@ func DefaultServerConfig() ServerConfig {
func defaultServerConfigYAML() *YAMLConfig {
return &YAMLConfig{
LogLevelStr: ptr(string(DefaultLogLevel)),
LogFormatStr: ptr(string(DefaultLogFormat)),
MaxQueryLenInLogs: ptr(DefaultMaxLoggedQueryLen),
EncodeLoggedQuery: ptr(DefaultEncodeLoggedQuery),
BehaviorConfig: BehaviorYAMLConfig{
Expand Down Expand Up @@ -270,6 +281,10 @@ func ValidateConfig(config ServerConfig) error {
if config.LogLevel().String() == "unknown" {
return fmt.Errorf("loglevel is invalid: %v\n", string(config.LogLevel()))
}
if strings.ToLower(fmt.Sprintf("%v", config.LogFormat())) != "text" &&
strings.ToLower(fmt.Sprintf("%v", config.LogFormat())) != "json" {
return fmt.Errorf("logformat is invalid: %v\n", config.LogFormat())
}
if config.RequireSecureTransport() && config.TLSCert() == "" && config.TLSKey() == "" {
return fmt.Errorf("require_secure_transport can only be `true` when a tls_key and tls_cert are provided.")
}
Expand All @@ -285,6 +300,7 @@ const (
WriteTimeoutKey = "net_write_timeout"
ReadOnlyKey = "read_only"
LogLevelKey = "log_level"
LogFormatKey = "log_format"
AutoCommitKey = "autocommit"
DoltTransactionCommitKey = "dolt_transaction_commit"
DataDirKey = "data_dir"
Expand Down
14 changes: 14 additions & 0 deletions go/libraries/doltcore/servercfg/yaml_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ type UserSessionVars struct {
// YAMLConfig is a ServerConfig implementation which is read from a yaml file
type YAMLConfig struct {
LogLevelStr *string `yaml:"log_level,omitempty"`
LogFormatStr *string `yaml:"log_format,omitempty"`
MaxQueryLenInLogs *int `yaml:"max_logged_query_len,omitempty"`
EncodeLoggedQuery *bool `yaml:"encode_logged_query,omitempty"`
BehaviorConfig BehaviorYAMLConfig `yaml:"behavior,omitempty"`
Expand Down Expand Up @@ -181,6 +182,7 @@ func ServerConfigAsYAMLConfig(cfg ServerConfig) *YAMLConfig {
autoGCBehavior := toAutoGCBehaviorYAML(cfg.AutoGCBehavior())
return &YAMLConfig{
LogLevelStr: ptr(string(cfg.LogLevel())),
LogFormatStr: ptr(string(cfg.LogFormat())),
MaxQueryLenInLogs: nillableIntPtr(cfg.MaxLoggedQueryLen()),
EncodeLoggedQuery: nillableBoolPtr(cfg.ShouldEncodeLoggedQuery()),
BehaviorConfig: BehaviorYAMLConfig{
Expand Down Expand Up @@ -251,6 +253,7 @@ func ServerConfigSetValuesAsYAMLConfig(cfg ServerConfig) *YAMLConfig {

return &YAMLConfig{
LogLevelStr: zeroIf(ptr(string(cfg.LogLevel())), !cfg.ValueSet(LogLevelKey)),
LogFormatStr: zeroIf(ptr(string(cfg.LogFormat())), !cfg.ValueSet(LogFormatKey)),
MaxQueryLenInLogs: zeroIf(ptr(cfg.MaxLoggedQueryLen()), !cfg.ValueSet(MaxLoggedQueryLenKey)),
EncodeLoggedQuery: zeroIf(ptr(cfg.ShouldEncodeLoggedQuery()), !cfg.ValueSet(ShouldEncodeLoggedQueryKey)),
BehaviorConfig: BehaviorYAMLConfig{
Expand Down Expand Up @@ -452,6 +455,9 @@ func (cfg YAMLConfig) withDefaultsFilledIn() YAMLConfig {
if withDefaults.LogLevelStr == nil {
withDefaults.LogLevelStr = defaults.LogLevelStr
}
if withDefaults.LogFormatStr == nil {
withDefaults.LogFormatStr = defaults.LogFormatStr
}
if withDefaults.MaxQueryLenInLogs == nil {
withDefaults.MaxQueryLenInLogs = defaults.MaxQueryLenInLogs
}
Expand Down Expand Up @@ -631,6 +637,14 @@ func (cfg YAMLConfig) LogLevel() LogLevel {

return LogLevel(*cfg.LogLevelStr)
}
// LogFormatStr returns the log format that the server will use.
func (cfg YAMLConfig) LogFormat() LogFormat {
if cfg.LogFormatStr == nil {
return DefaultLogFormat
}

return LogFormat(*cfg.LogFormatStr)
}

// MaxConnections returns the maximum number of simultaneous connections the server will allow. The default is 1
func (cfg YAMLConfig) MaxConnections() uint64 {
Expand Down
3 changes: 2 additions & 1 deletion go/libraries/doltcore/servercfg/yaml_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ var trueValue = true
func TestUnmarshall(t *testing.T) {
testStr := `
log_level: info

log_format: text
behavior:
read_only: false
autocommit: true
Expand Down Expand Up @@ -329,6 +329,7 @@ func TestYAMLConfigDefaults(t *testing.T) {
assert.Equal(t, uint64(DefaultTimeout), cfg.ReadTimeout())
assert.Equal(t, DefaultReadOnly, cfg.ReadOnly())
assert.Equal(t, DefaultLogLevel, cfg.LogLevel())
assert.Equal(t, DefaultLogFormat, cfg.LogFormat())
assert.Equal(t, DefaultAutoCommit, cfg.AutoCommit())
assert.Equal(t, DefaultDoltTransactionCommit, cfg.DoltTransactionCommit())
assert.Equal(t, uint64(DefaultMaxConnections), cfg.MaxConnections())
Expand Down
28 changes: 28 additions & 0 deletions integration-tests/bats/sql-server.bats
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,34 @@ EOF
dolt sql -q "show databases;"
stop_sql_server
}
@test "sql-server: logformats are case insensitive" {
Copy link
Contributor

@timsehn timsehn Feb 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need a test here to assert that the log outputted in json format.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@timsehn Added.

# assert that logformat on command line is not case sensitive
cd repo1
PORT=$( definePORT )
dolt sql-server --logformat jSon --port=$PORT --socket "dolt.$PORT.sock" > log.txt 2>&1 &
SERVER_PID=$!
wait_for_connection $PORT 8500
dolt sql -q "show databases;"
stop_sql_server

# Assert that log is in JSON format (checking if logs contain `{...}`)
grep -q '^{.*}$' log.txt
# assert that logformat in yaml config is not case sensitive
cat >config.yml <<EOF
log_format: teXt
behavior:
disable_client_multi_statements: true
listener:
host: "0.0.0.0"
port: $PORT
EOF
dolt sql-server --config ./config.yml --socket "dolt.$PORT.sock" &
SERVER_PID=$!
wait_for_connection $PORT 8500
dolt sql -q "show databases;"
stop_sql_server
}


@test "sql-server: server assumes existing user" {
cd repo1
Expand Down