From 85913affc6ac8bf1aff3c389f138b60f91f28080 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Fri, 21 Jan 2022 00:08:45 +0800 Subject: [PATCH] feature: support log to remote syslog server --- pkg/logger/extern/doc.go | 15 ++++++++ pkg/logger/extern/syslog.go | 67 ++++++++++++++++++++++++++++++++++ pkg/logger/models/actionlog.go | 11 ++++++ pkg/logger/options/options.go | 27 ++++++++++++++ pkg/logger/service/handlers.go | 2 + pkg/logger/service/service.go | 6 +++ 6 files changed, 128 insertions(+) create mode 100644 pkg/logger/extern/doc.go create mode 100644 pkg/logger/extern/syslog.go diff --git a/pkg/logger/extern/doc.go b/pkg/logger/extern/doc.go new file mode 100644 index 0000000000..27aaf4a281 --- /dev/null +++ b/pkg/logger/extern/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package extern // import "yunion.io/x/onecloud/pkg/logger/extern" diff --git a/pkg/logger/extern/syslog.go b/pkg/logger/extern/syslog.go new file mode 100644 index 0000000000..53d7c53d32 --- /dev/null +++ b/pkg/logger/extern/syslog.go @@ -0,0 +1,67 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package extern + +import ( + "log/syslog" + "strings" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" +) + +var ( + sysLog *syslog.Writer +) + +func InitSyslog(url string) error { + proto := "tcp" + addr := url + tag := "cloudaudit" + + if strings.HasPrefix(url, "tcp://") { + proto = "tcp" + addr = url[6:] + } else if strings.HasPrefix(url, "udp://") { + proto = "udp" + addr = url[6:] + } + + if strings.Contains(addr, "@") { + parts := strings.Split(addr, "@") + addr = parts[0] + tag = parts[1] + } + + var err error + sysLog, err = syslog.Dial(proto, addr, syslog.LOG_ERR|syslog.LOG_INFO, tag) + if err != nil { + return errors.Wrap(err, "syslog.Dial") + } + log.Infof("Start syslog to %s://%s@%s", proto, addr, tag) + return nil +} + +func Error(msg string) { + if sysLog != nil { + sysLog.Err(msg) + } +} + +func Info(msg string) { + if sysLog != nil { + sysLog.Info(msg) + } +} diff --git a/pkg/logger/models/actionlog.go b/pkg/logger/models/actionlog.go index 3afccf2a74..647e936172 100644 --- a/pkg/logger/models/actionlog.go +++ b/pkg/logger/models/actionlog.go @@ -16,6 +16,7 @@ package models import ( "context" + "fmt" "time" "yunion.io/x/jsonutils" @@ -28,6 +29,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/logger/extern" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" ) @@ -106,6 +108,15 @@ func (action *SActionlog) CustomizeCreate(ctx context.Context, userCred mcclient } func (self *SActionlog) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { + self.SOpsLog.PostCreate(ctx, userCred, ownerId, query, data) + msg := fmt.Sprintf("#%d ", self.Id) + msg += fmt.Sprintf("%s %s %s %s %s ", self.Service, self.ObjType, self.ObjName, self.ObjId, self.Action) + msg += fmt.Sprintf("%s %s %s %s %s %s", self.Domain, self.Project, self.User, self.OwnerDomainId, self.OwnerProjectId, self.Notes) + if self.Success { + extern.Info(msg) + } else { + extern.Error(msg) + } for k, v := range map[string]string{ "service": self.Service, "action": self.Action, diff --git a/pkg/logger/options/options.go b/pkg/logger/options/options.go index b3da800424..dc2090657c 100644 --- a/pkg/logger/options/options.go +++ b/pkg/logger/options/options.go @@ -16,14 +16,41 @@ package options import ( common_options "yunion.io/x/onecloud/pkg/cloudcommon/options" + "yunion.io/x/onecloud/pkg/logger/extern" ) type SLoggerOptions struct { common_options.CommonOptions common_options.DBOptions + + SyslogUrl string `help:"external syslog url, e.g. tcp://localhost:1234@cloud"` } var ( Options SLoggerOptions ) + +func OnOptionsChange(oldOptions, newOptions interface{}) bool { + oldOpts := oldOptions.(*SLoggerOptions) + newOpts := newOptions.(*SLoggerOptions) + + changed := false + if common_options.OnBaseOptionsChange(&oldOpts.BaseOptions, &newOpts.BaseOptions) { + changed = true + } + + if common_options.OnDBOptionsChange(&oldOpts.DBOptions, &newOpts.DBOptions) { + changed = true + } + + if oldOpts.SyslogUrl != newOpts.SyslogUrl { + err := extern.InitSyslog(newOpts.SyslogUrl) + if err != nil { + // reset syslog writer error, restart the service to take effect + changed = true + } + } + + return changed +} diff --git a/pkg/logger/service/handlers.go b/pkg/logger/service/handlers.go index b7095703fe..e09fa1519c 100644 --- a/pkg/logger/service/handlers.go +++ b/pkg/logger/service/handlers.go @@ -36,6 +36,8 @@ func initHandlers(app *appsrv.Application) { } for _, manager := range []db.IModelManager{ + db.Metadata, + models.ActionLog, models.BaremetalEventManager, } { diff --git a/pkg/logger/service/service.go b/pkg/logger/service/service.go index e48221ad21..ca2ba60ef0 100644 --- a/pkg/logger/service/service.go +++ b/pkg/logger/service/service.go @@ -26,6 +26,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" common_options "yunion.io/x/onecloud/pkg/cloudcommon/options" + "yunion.io/x/onecloud/pkg/logger/extern" "yunion.io/x/onecloud/pkg/logger/models" "yunion.io/x/onecloud/pkg/logger/options" _ "yunion.io/x/onecloud/pkg/logger/policy" @@ -44,6 +45,7 @@ func StartService() { app_common.InitAuth(commonOpts, func() { log.Infof("Auth complete!!") }) + common_options.StartOptionManager(opts, opts.ConfigSyncPeriodSeconds, api.SERVICE_TYPE, "", options.OnOptionsChange) app := app_common.InitApp(baseOpts, true) @@ -56,5 +58,9 @@ func StartService() { // models.StartNotifyToWebsocketWorker() + if len(opts.SyslogUrl) > 0 { + extern.InitSyslog(opts.SyslogUrl) + } + app_common.ServeForever(app, baseOpts) }