[MM-54319] Add AdvancedLoggingJSON setting to system console (#24733)
* Add AdvancedLoggingJSON setting to system console * Apply suggestions from code review Co-authored-by: Doug Lauder <wiggin77@warpmail.net> * Add validation for AdvancedLoggingJSON --------- Co-authored-by: Doug Lauder <wiggin77@warpmail.net> Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
0844968d81
Коммит
671cf6cc3d
@@ -8730,6 +8730,14 @@
|
||||
"id": "model.config.is_valid.localization.available_locales.app_error",
|
||||
"translation": "Available Languages must contain Default Client Language."
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.log.advanced_logging.json",
|
||||
"translation": "Failed to parse JSON: {{.Error}}"
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.log.advanced_logging.parse",
|
||||
"translation": "Invalid format: {{.Error}}"
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.login_attempts.app_error",
|
||||
"translation": "Invalid maximum login attempts for service settings. Must be a positive number."
|
||||
|
||||
@@ -1285,6 +1285,21 @@ func NewLogSettings() *LogSettings {
|
||||
return settings
|
||||
}
|
||||
|
||||
func (s *LogSettings) isValid() *AppError {
|
||||
cfg := make(mlog.LoggerConfiguration)
|
||||
err := json.Unmarshal(s.GetAdvancedLoggingConfig(), &cfg)
|
||||
if err != nil {
|
||||
return NewAppError("LogSettings.isValid", "model.config.is_valid.log.advanced_logging.json", map[string]any{"Error": err}, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
|
||||
err = cfg.IsValid()
|
||||
if err != nil {
|
||||
return NewAppError("LogSettings.isValid", "model.config.is_valid.log.advanced_logging.parse", map[string]any{"Error": err}, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LogSettings) SetDefaults() {
|
||||
if s.EnableConsole == nil {
|
||||
s.EnableConsole = NewBool(true)
|
||||
@@ -3551,6 +3566,10 @@ func (o *Config) IsValid() *AppError {
|
||||
return appErr
|
||||
}
|
||||
|
||||
if appErr := o.LogSettings.isValid(); appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
if appErr := o.LocalizationSettings.isValid(); appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
@@ -1208,6 +1208,109 @@ func TestLdapSettingsIsValid(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogSettingsIsValid(t *testing.T) {
|
||||
for name, test := range map[string]struct {
|
||||
LogSettings LogSettings
|
||||
ExpectError bool
|
||||
}{
|
||||
"empty": {
|
||||
LogSettings: LogSettings{},
|
||||
ExpectError: false,
|
||||
},
|
||||
"AdvancedLoggingJSON contains empty string": {
|
||||
LogSettings: LogSettings{
|
||||
AdvancedLoggingJSON: json.RawMessage(``),
|
||||
},
|
||||
ExpectError: false,
|
||||
},
|
||||
"AdvancedLoggingJSON contains empty JSON": {
|
||||
LogSettings: LogSettings{
|
||||
AdvancedLoggingJSON: json.RawMessage(`{}`),
|
||||
},
|
||||
ExpectError: false,
|
||||
},
|
||||
"AdvancedLoggingJSON has JSON error ": {
|
||||
LogSettings: LogSettings{
|
||||
AdvancedLoggingJSON: json.RawMessage(`
|
||||
{
|
||||
"foo": "bar",
|
||||
`),
|
||||
},
|
||||
ExpectError: true,
|
||||
},
|
||||
"AdvancedLoggingJSON has missing target": {
|
||||
LogSettings: LogSettings{
|
||||
AdvancedLoggingJSON: json.RawMessage(`
|
||||
{
|
||||
"foo": "bar",
|
||||
}
|
||||
`),
|
||||
},
|
||||
ExpectError: true,
|
||||
},
|
||||
"AdvancedLoggingJSON has an unknown Type": {
|
||||
LogSettings: LogSettings{
|
||||
AdvancedLoggingJSON: json.RawMessage(`
|
||||
{
|
||||
"console-log": {
|
||||
"Type": "XYZ",
|
||||
"Format": "json",
|
||||
"Levels": [
|
||||
{"ID": 10, "Name": "stdlog", "Stacktrace": false},
|
||||
{"ID": 5, "Name": "debug", "Stacktrace": false},
|
||||
{"ID": 4, "Name": "info", "Stacktrace": false, "color": 36},
|
||||
{"ID": 3, "Name": "warn", "Stacktrace": false, "color": 33},
|
||||
{"ID": 2, "Name": "error", "Stacktrace": true, "color": 31},
|
||||
{"ID": 1, "Name": "fatal", "Stacktrace": true},
|
||||
{"ID": 0, "Name": "panic", "Stacktrace": true}
|
||||
],
|
||||
"Options": {
|
||||
"Out": "stdout"
|
||||
},
|
||||
"MaxQueueSize": 1000
|
||||
}
|
||||
}
|
||||
`),
|
||||
},
|
||||
ExpectError: true,
|
||||
},
|
||||
"AdvancedLoggingJSON is valid": {
|
||||
LogSettings: LogSettings{
|
||||
AdvancedLoggingJSON: json.RawMessage(`
|
||||
{
|
||||
"console-log": {
|
||||
"Type": "console",
|
||||
"Format": "json",
|
||||
"Levels": [
|
||||
{"ID": 5, "Name": "debug", "Stacktrace": false},
|
||||
{"ID": 4, "Name": "info", "Stacktrace": false, "color": 36},
|
||||
{"ID": 3, "Name": "warn", "Stacktrace": false, "color": 33},
|
||||
{"ID": 2, "Name": "error", "Stacktrace": true, "color": 31}
|
||||
],
|
||||
"Options": {
|
||||
"Out": "stdout"
|
||||
},
|
||||
"MaxQueueSize": 1000
|
||||
}
|
||||
}
|
||||
`),
|
||||
},
|
||||
ExpectError: false,
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
test.LogSettings.SetDefaults()
|
||||
|
||||
appErr := test.LogSettings.isValid()
|
||||
if test.ExpectError {
|
||||
assert.NotNil(t, appErr)
|
||||
} else {
|
||||
assert.Nil(t, appErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigSanitize(t *testing.T) {
|
||||
c := Config{}
|
||||
c.SetDefaults()
|
||||
|
||||
@@ -7,7 +7,6 @@ package mlog
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -16,6 +15,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/mattermost/logr/v2"
|
||||
logrcfg "github.com/mattermost/logr/v2/config"
|
||||
)
|
||||
@@ -68,6 +69,21 @@ func (lc LoggerConfiguration) Append(cfg LoggerConfiguration) {
|
||||
}
|
||||
}
|
||||
|
||||
func (lc LoggerConfiguration) IsValid() error {
|
||||
logger, err := logr.New()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create logger")
|
||||
}
|
||||
defer logger.Shutdown()
|
||||
|
||||
err = logrcfg.ConfigureTargets(logger, lc, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "logger configuration is invalid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lc LoggerConfiguration) toTargetCfg() map[string]logrcfg.TargetCfg {
|
||||
tcfg := make(map[string]logrcfg.TargetCfg)
|
||||
for k, v := range lc {
|
||||
|
||||
@@ -1863,6 +1863,49 @@ const AdminDefinition = {
|
||||
},
|
||||
isDisabled: it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.ENVIRONMENT.LOGGING)),
|
||||
},
|
||||
{
|
||||
type: Constants.SettingsTypes.TYPE_LONG_TEXT,
|
||||
key: 'LogSettings.AdvancedLoggingJSON',
|
||||
label: t('admin.log.AdvancedLoggingJSONTitle'),
|
||||
label_default: 'Advanced Logging:',
|
||||
help_text: t('admin.log.AdvancedLoggingJSONDescription'),
|
||||
help_text_default: 'The JSON configuration for Advanced Logging. Please see <link>documentation</link> to learn more about Advanced Logging and the JSON format it uses.',
|
||||
help_text_markdown: false,
|
||||
help_text_values: {
|
||||
link: (msg) => (
|
||||
<ExternalLink
|
||||
location='admin_console'
|
||||
href={DocLinks.ADVANCED_LOGGING}
|
||||
>
|
||||
{msg}
|
||||
</ExternalLink>
|
||||
),
|
||||
},
|
||||
placeholder: t('admin.log.AdvancedLoggingJSONPlaceholder'),
|
||||
placeholder_default: 'Enter your JSON configuration',
|
||||
isDisabled: it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.ENVIRONMENT.LOGGING)),
|
||||
validate: (value) => {
|
||||
const valid = new ValidationResult(true, '', '');
|
||||
if (!value) {
|
||||
return valid;
|
||||
}
|
||||
try {
|
||||
JSON.parse(value);
|
||||
return valid;
|
||||
} catch (error) {
|
||||
return new ValidationResult(false, '', error.message);
|
||||
}
|
||||
},
|
||||
onConfigLoad: (configVal) => JSON.stringify(configVal, null, ' '),
|
||||
onConfigSave: (displayVal) => {
|
||||
// Handle case where field is empty
|
||||
if (!displayVal) {
|
||||
return {undefined};
|
||||
}
|
||||
|
||||
return JSON.parse(displayVal);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1373,6 +1373,9 @@
|
||||
"admin.license.warn.renew": "Renew",
|
||||
"admin.lockTeammateNameDisplay": "Lock Teammate Name Display for all users: ",
|
||||
"admin.lockTeammateNameDisplayHelpText": "When true, disables users' ability to change settings under <strong>Settings > Display > Teammate Name Display</strong>.",
|
||||
"admin.log.AdvancedLoggingJSONDescription": "The JSON configuration for Advanced Logging. Please see <link>documentation</link> to learn more about Advanced Logging and the JSON format it uses.",
|
||||
"admin.log.AdvancedLoggingJSONPlaceholder": "Enter your JSON configuration",
|
||||
"admin.log.AdvancedLoggingJSONTitle": "Advanced Logging:",
|
||||
"admin.log.consoleDescription": "Typically set to false in production. Developers may set this field to true to output log messages to console based on the console level option. If true, server writes messages to the standard output stream (stdout). Changing this setting requires a server restart before taking effect.",
|
||||
"admin.log.consoleJsonTitle": "Output console logs as JSON:",
|
||||
"admin.log.consoleTitle": "Output logs to console: ",
|
||||
|
||||
@@ -1088,6 +1088,7 @@ export const HostedCustomerLinks = {
|
||||
|
||||
export const DocLinks = {
|
||||
ABOUT_TEAMS: 'https://docs.mattermost.com/welcome/about-teams.html#team-url',
|
||||
ADVANCED_LOGGING: 'https://mattermost.com/pl/advanced-logging',
|
||||
CONFIGURE_DOCUMENT_CONTENT_SEARCH: 'https://mattermost.com/pl/configure-document-content-search',
|
||||
CONFIGURE_AD_LDAP_QUERY_TIMEOUT: 'https://mattermost.com/pl/configure-ad-ldap-query-timeout',
|
||||
CONFIGURE_OVERRIDE_SAML_BIND_DATA_WITH_LDAP: 'https://mattermost.com/pl/configure-override-saml-bind-data-with-ldap',
|
||||
|
||||
Ссылка в новой задаче
Block a user