Full Mattermost server source with integrated Community Enterprise features. Includes vendor directory for offline/air-gapped builds. Structure: - enterprise-impl/: Enterprise feature implementations - enterprise-community/: Init files that register implementations - enterprise/: Bridge imports (community_imports.go) - vendor/: All dependencies for offline builds Build (online): go build ./cmd/mattermost Build (offline/air-gapped): go build -mod=vendor ./cmd/mattermost 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
215 lines
5.2 KiB
Go
215 lines
5.2 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
|
"github.com/mattermost/mattermost/server/v8/channels/utils/fileutils"
|
|
)
|
|
|
|
const (
|
|
LogRotateSizeMB = 100
|
|
LogCompress = true
|
|
LogRotateMaxAge = 0
|
|
LogRotateMaxBackups = 0
|
|
LogFilename = "mattermost.log"
|
|
LogMinLevelLen = 5
|
|
LogMinMsgLen = 45
|
|
LogDelim = " "
|
|
LogEnableCaller = true
|
|
)
|
|
|
|
type fileLocationFunc func(string) string
|
|
|
|
func MloggerConfigFromLoggerConfig(s *model.LogSettings, configSrc LogConfigSrc, getFileFunc fileLocationFunc) (mlog.LoggerConfiguration, error) {
|
|
cfg := make(mlog.LoggerConfiguration)
|
|
|
|
var targetCfg mlog.TargetCfg
|
|
var err error
|
|
|
|
// add the simple logging config
|
|
if *s.EnableConsole {
|
|
targetCfg, err = makeSimpleConsoleTarget(*s.ConsoleLevel, *s.ConsoleJson, *s.EnableColor)
|
|
if err != nil {
|
|
return cfg, err
|
|
}
|
|
cfg["_defConsole"] = targetCfg
|
|
}
|
|
|
|
if *s.EnableFile {
|
|
targetCfg, err = makeSimpleFileTarget(getFileFunc(*s.FileLocation), *s.FileLevel, *s.FileJson)
|
|
if err != nil {
|
|
return cfg, err
|
|
}
|
|
cfg["_defFile"] = targetCfg
|
|
}
|
|
|
|
if configSrc == nil {
|
|
return cfg, nil
|
|
}
|
|
|
|
// add advanced logging config
|
|
cfgAdv := configSrc.Get()
|
|
cfg.Append(cfgAdv)
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func MloggerConfigFromAuditConfig(auditSettings model.ExperimentalAuditSettings, configSrc LogConfigSrc) (mlog.LoggerConfiguration, error) {
|
|
cfg := make(mlog.LoggerConfiguration)
|
|
|
|
var targetCfg mlog.TargetCfg
|
|
var err error
|
|
|
|
// add the simple audit config
|
|
if *auditSettings.FileEnabled {
|
|
targetCfg, err = makeSimpleFileTarget(*auditSettings.FileName, "error", true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// apply audit specific levels
|
|
targetCfg.Levels = []mlog.Level{mlog.LvlAuditAPI, mlog.LvlAuditContent, mlog.LvlAuditPerms, mlog.LvlAuditCLI}
|
|
|
|
// apply audit specific formatting
|
|
targetCfg.FormatOptions = json.RawMessage(`{"disable_timestamp": false, "disable_msg": true, "disable_stacktrace": true, "disable_level": true}`)
|
|
|
|
cfg["_defAudit"] = targetCfg
|
|
}
|
|
|
|
if configSrc == nil {
|
|
return cfg, nil
|
|
}
|
|
|
|
// add advanced audit config
|
|
cfgAdv := configSrc.Get()
|
|
cfg.Append(cfgAdv)
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func GetLogFileLocation(fileLocation string) string {
|
|
if fileLocation == "" {
|
|
fileLocation, _ = fileutils.FindDir("logs")
|
|
}
|
|
|
|
return filepath.Join(fileLocation, LogFilename)
|
|
}
|
|
|
|
func makeSimpleConsoleTarget(level string, outputJSON bool, color bool) (mlog.TargetCfg, error) {
|
|
levels, err := stdLevels(level)
|
|
if err != nil {
|
|
return mlog.TargetCfg{}, err
|
|
}
|
|
|
|
target := mlog.TargetCfg{
|
|
Type: "console",
|
|
Levels: levels,
|
|
Options: json.RawMessage(`{"out": "stdout"}`),
|
|
MaxQueueSize: 1000,
|
|
}
|
|
|
|
if outputJSON {
|
|
target.Format = "json"
|
|
target.FormatOptions = makeJSONFormatOptions()
|
|
} else {
|
|
target.Format = "plain"
|
|
target.FormatOptions = makePlainFormatOptions(color)
|
|
}
|
|
return target, nil
|
|
}
|
|
|
|
func makeSimpleFileTarget(filename string, level string, json bool) (mlog.TargetCfg, error) {
|
|
levels, err := stdLevels(level)
|
|
if err != nil {
|
|
return mlog.TargetCfg{}, err
|
|
}
|
|
|
|
fileOpts, err := makeFileOptions(filename)
|
|
if err != nil {
|
|
return mlog.TargetCfg{}, fmt.Errorf("cannot encode file options: %w", err)
|
|
}
|
|
|
|
target := mlog.TargetCfg{
|
|
Type: "file",
|
|
Levels: levels,
|
|
Options: fileOpts,
|
|
MaxQueueSize: 1000,
|
|
}
|
|
|
|
if json {
|
|
target.Format = "json"
|
|
target.FormatOptions = makeJSONFormatOptions()
|
|
} else {
|
|
target.Format = "plain"
|
|
target.FormatOptions = makePlainFormatOptions(false)
|
|
}
|
|
return target, nil
|
|
}
|
|
|
|
func stdLevels(level string) ([]mlog.Level, error) {
|
|
stdLevel, err := stringToStdLevel(level)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var levels []mlog.Level
|
|
for _, l := range mlog.StdAll {
|
|
if l.ID <= stdLevel.ID {
|
|
levels = append(levels, l)
|
|
}
|
|
}
|
|
return levels, nil
|
|
}
|
|
|
|
func stringToStdLevel(level string) (mlog.Level, error) {
|
|
level = strings.ToLower(level)
|
|
for _, l := range mlog.StdAll {
|
|
if l.Name == level {
|
|
return l, nil
|
|
}
|
|
}
|
|
return mlog.Level{}, fmt.Errorf("%s is not a standard level", level)
|
|
}
|
|
|
|
func makeJSONFormatOptions() json.RawMessage {
|
|
str := fmt.Sprintf(`{"enable_caller": %t}`, LogEnableCaller)
|
|
return json.RawMessage(str)
|
|
}
|
|
|
|
func makePlainFormatOptions(enableColor bool) json.RawMessage {
|
|
str := fmt.Sprintf(`{"delim": "%s", "min_level_len": %d, "min_msg_len": %d, "enable_color": %t, "enable_caller": %t}`,
|
|
LogDelim, LogMinLevelLen, LogMinMsgLen, enableColor, LogEnableCaller)
|
|
return json.RawMessage(str)
|
|
}
|
|
|
|
func makeFileOptions(filename string) (json.RawMessage, error) {
|
|
opts := struct {
|
|
Filename string `json:"filename"`
|
|
Max_size int `json:"max_size"`
|
|
Max_age int `json:"max_age"`
|
|
Max_backups int `json:"max_backups"`
|
|
Compress bool `json:"compress"`
|
|
}{
|
|
Filename: filename,
|
|
Max_size: LogRotateSizeMB,
|
|
Max_age: LogRotateMaxAge,
|
|
Max_backups: LogRotateMaxBackups,
|
|
Compress: LogCompress,
|
|
}
|
|
|
|
b, err := json.Marshal(opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return json.RawMessage(b), nil
|
|
}
|