From 83a3ac089cff0d05559e6ba5c2c60b09f5cae176 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Tue, 3 Jul 2018 09:58:28 -0700 Subject: MM-11029 Adding plugin logging functionality. (#9034) * Capturing stdout, stderr of plugins in logs. * Cleanup go-plugin debug logs. * Adding logging to plugin API * Generating mocks. * godoc convention --- plugin/api.go | 24 +++++ plugin/client_rpc.go | 29 +++--- plugin/client_rpc_generated.go | 194 +++++++++++++++++++++++++++++++++++++ plugin/hclog_adapter.go | 36 ++++++- plugin/interface_generator/main.go | 21 +++- plugin/plugintest/api.go | 34 ++++++- plugin/plugintest/hooks.go | 2 +- plugin/supervisor.go | 7 +- 8 files changed, 316 insertions(+), 31 deletions(-) (limited to 'plugin') diff --git a/plugin/api.go b/plugin/api.go index 842cef4f6..81a27c330 100644 --- a/plugin/api.go +++ b/plugin/api.go @@ -119,6 +119,30 @@ type API interface { // payload is the data sent with the event. Interface values must be primitive Go types or mattermost-server/model types // broadcast determines to which users to send the event PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *model.WebsocketBroadcast) + + // LogDebug writes a log message to the Mattermost server log file. + // Appropriate context such as the plugin name will already be added as fields so plugins + // do not need to add that info. + // keyValuePairs should be primitive go types or other values that can be encoded by encoding/gob + LogDebug(msg string, keyValuePairs ...interface{}) + + // LogInfo writes a log message to the Mattermost server log file. + // Appropriate context such as the plugin name will already be added as fields so plugins + // do not need to add that info. + // keyValuePairs should be primitive go types or other values that can be encoded by encoding/gob + LogInfo(msg string, keyValuePairs ...interface{}) + + // LogError writes a log message to the Mattermost server log file. + // Appropriate context such as the plugin name will already be added as fields so plugins + // do not need to add that info. + // keyValuePairs should be primitive go types or other values that can be encoded by encoding/gob + LogError(msg string, keyValuePairs ...interface{}) + + // LogWarn writes a log message to the Mattermost server log file. + // Appropriate context such as the plugin name will already be added as fields so plugins + // do not need to add that info. + // keyValuePairs should be primitive go types or other values that can be encoded by encoding/gob + LogWarn(msg string, keyValuePairs ...interface{}) } var Handshake = plugin.HandshakeConfig{ diff --git a/plugin/client_rpc.go b/plugin/client_rpc.go index 159d41201..f58bbd22b 100644 --- a/plugin/client_rpc.go +++ b/plugin/client_rpc.go @@ -9,9 +9,12 @@ import ( "bytes" "encoding/gob" "encoding/json" + "fmt" "io/ioutil" + "log" "net/http" "net/rpc" + "os" "reflect" "github.com/hashicorp/go-plugin" @@ -33,7 +36,6 @@ type HooksRPCServer struct { impl interface{} muxBroker *plugin.MuxBroker apiRPCClient *APIRPCClient - log *mlog.Logger } // Implements hashicorp/go-plugin/plugin.Plugin interface to connect the hooks of a plugin @@ -156,24 +158,11 @@ func (g *HooksRPCClient) OnActivate() error { func (s *HooksRPCServer) OnActivate(args *OnActivateArgs, returns *OnActivateReturns) error { connection, err := s.muxBroker.Dial(args.APIMuxId) if err != nil { - return err // Where does this go? + return err } - // Settings for this should come from the parent process, for now just set it up - // though stdout. - logger := mlog.NewLogger(&mlog.LoggerConfiguration{ - EnableConsole: true, - ConsoleJson: true, - ConsoleLevel: mlog.LevelDebug, - EnableFile: false, - }) - logger = logger.With(mlog.Bool("plugin_subprocess", true)) - - s.log = logger - s.apiRPCClient = &APIRPCClient{ client: rpc.NewClient(connection), - log: logger, } if mmplugin, ok := s.impl.(interface { @@ -185,6 +174,10 @@ func (s *HooksRPCServer) OnActivate(args *OnActivateArgs, returns *OnActivateRet mmplugin.OnConfigurationChange() } + // Capture output of standard logger because go-plugin + // redirects it. + log.SetOutput(os.Stderr) + if hook, ok := s.impl.(interface { OnActivate() error }); ok { @@ -293,7 +286,7 @@ func (g *HooksRPCClient) ServeHTTP(w http.ResponseWriter, r *http.Request) { Request: forwardedRequest, RequestBodyStream: requestBodyStreamId, }, nil); err != nil { - mlog.Error("Plugin failed to ServeHTTP, RPC call failed", mlog.Err(err)) + g.log.Error("Plugin failed to ServeHTTP, RPC call failed", mlog.Err(err)) http.Error(w, "500 internal server error", http.StatusInternalServerError) } return @@ -302,7 +295,7 @@ func (g *HooksRPCClient) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s *HooksRPCServer) ServeHTTP(args *ServeHTTPArgs, returns *struct{}) error { connection, err := s.muxBroker.Dial(args.ResponseWriterStream) if err != nil { - s.log.Debug("Can't connect to remote response writer stream", mlog.Err(err)) + fmt.Fprintf(os.Stderr, "[ERROR] Can't connect to remote response writer stream, error: %v", err.Error()) return err } w := ConnectHTTPResponseWriter(connection) @@ -312,7 +305,7 @@ func (s *HooksRPCServer) ServeHTTP(args *ServeHTTPArgs, returns *struct{}) error if args.RequestBodyStream != 0 { connection, err := s.muxBroker.Dial(args.RequestBodyStream) if err != nil { - s.log.Debug("Can't connect to remote response writer stream", mlog.Err(err)) + fmt.Fprintf(os.Stderr, "[ERROR] Can't connect to remote request body stream, error: %v", err.Error()) return err } r.Body = ConnectIOReader(connection) diff --git a/plugin/client_rpc_generated.go b/plugin/client_rpc_generated.go index 9880814b2..897d6be04 100644 --- a/plugin/client_rpc_generated.go +++ b/plugin/client_rpc_generated.go @@ -7,6 +7,8 @@ package plugin import ( + "fmt" + "github.com/mattermost/mattermost-server/mlog" "github.com/mattermost/mattermost-server/model" ) @@ -38,6 +40,8 @@ func (s *HooksRPCServer) OnDeactivate(args *OnDeactivateArgs, returns *OnDeactiv OnDeactivate() error }); ok { returns.A = hook.OnDeactivate() + } else { + return fmt.Errorf("Hook OnDeactivate called but not implemented.") } return nil } @@ -69,6 +73,8 @@ func (s *HooksRPCServer) OnConfigurationChange(args *OnConfigurationChangeArgs, OnConfigurationChange() error }); ok { returns.A = hook.OnConfigurationChange() + } else { + return fmt.Errorf("Hook OnConfigurationChange called but not implemented.") } return nil } @@ -102,6 +108,8 @@ func (s *HooksRPCServer) ExecuteCommand(args *ExecuteCommandArgs, returns *Execu ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *model.AppError) }); ok { returns.A, returns.B = hook.ExecuteCommand(args.A) + } else { + return fmt.Errorf("Hook ExecuteCommand called but not implemented.") } return nil } @@ -135,6 +143,8 @@ func (s *HooksRPCServer) MessageWillBePosted(args *MessageWillBePostedArgs, retu MessageWillBePosted(post *model.Post) (*model.Post, string) }); ok { returns.A, returns.B = hook.MessageWillBePosted(args.A) + } else { + return fmt.Errorf("Hook MessageWillBePosted called but not implemented.") } return nil } @@ -169,6 +179,8 @@ func (s *HooksRPCServer) MessageWillBeUpdated(args *MessageWillBeUpdatedArgs, re MessageWillBeUpdated(newPost, oldPost *model.Post) (*model.Post, string) }); ok { returns.A, returns.B = hook.MessageWillBeUpdated(args.A, args.B) + } else { + return fmt.Errorf("Hook MessageWillBeUpdated called but not implemented.") } return nil } @@ -200,6 +212,8 @@ func (s *HooksRPCServer) MessageHasBeenPosted(args *MessageHasBeenPostedArgs, re MessageHasBeenPosted(post *model.Post) }); ok { hook.MessageHasBeenPosted(args.A) + } else { + return fmt.Errorf("Hook MessageHasBeenPosted called but not implemented.") } return nil } @@ -232,6 +246,8 @@ func (s *HooksRPCServer) MessageHasBeenUpdated(args *MessageHasBeenUpdatedArgs, MessageHasBeenUpdated(newPost, oldPost *model.Post) }); ok { hook.MessageHasBeenUpdated(args.A, args.B) + } else { + return fmt.Errorf("Hook MessageHasBeenUpdated called but not implemented.") } return nil } @@ -258,6 +274,8 @@ func (s *APIRPCServer) RegisterCommand(args *RegisterCommandArgs, returns *Regis RegisterCommand(command *model.Command) error }); ok { returns.A = hook.RegisterCommand(args.A) + } else { + return fmt.Errorf("API RegisterCommand called but not implemented.") } return nil } @@ -285,6 +303,8 @@ func (s *APIRPCServer) UnregisterCommand(args *UnregisterCommandArgs, returns *U UnregisterCommand(teamId, trigger string) error }); ok { returns.A = hook.UnregisterCommand(args.A, args.B) + } else { + return fmt.Errorf("API UnregisterCommand called but not implemented.") } return nil } @@ -312,6 +332,8 @@ func (s *APIRPCServer) CreateUser(args *CreateUserArgs, returns *CreateUserRetur CreateUser(user *model.User) (*model.User, *model.AppError) }); ok { returns.A, returns.B = hook.CreateUser(args.A) + } else { + return fmt.Errorf("API CreateUser called but not implemented.") } return nil } @@ -338,6 +360,8 @@ func (s *APIRPCServer) DeleteUser(args *DeleteUserArgs, returns *DeleteUserRetur DeleteUser(userId string) *model.AppError }); ok { returns.A = hook.DeleteUser(args.A) + } else { + return fmt.Errorf("API DeleteUser called but not implemented.") } return nil } @@ -365,6 +389,8 @@ func (s *APIRPCServer) GetUser(args *GetUserArgs, returns *GetUserReturns) error GetUser(userId string) (*model.User, *model.AppError) }); ok { returns.A, returns.B = hook.GetUser(args.A) + } else { + return fmt.Errorf("API GetUser called but not implemented.") } return nil } @@ -392,6 +418,8 @@ func (s *APIRPCServer) GetUserByEmail(args *GetUserByEmailArgs, returns *GetUser GetUserByEmail(email string) (*model.User, *model.AppError) }); ok { returns.A, returns.B = hook.GetUserByEmail(args.A) + } else { + return fmt.Errorf("API GetUserByEmail called but not implemented.") } return nil } @@ -419,6 +447,8 @@ func (s *APIRPCServer) GetUserByUsername(args *GetUserByUsernameArgs, returns *G GetUserByUsername(name string) (*model.User, *model.AppError) }); ok { returns.A, returns.B = hook.GetUserByUsername(args.A) + } else { + return fmt.Errorf("API GetUserByUsername called but not implemented.") } return nil } @@ -446,6 +476,8 @@ func (s *APIRPCServer) UpdateUser(args *UpdateUserArgs, returns *UpdateUserRetur UpdateUser(user *model.User) (*model.User, *model.AppError) }); ok { returns.A, returns.B = hook.UpdateUser(args.A) + } else { + return fmt.Errorf("API UpdateUser called but not implemented.") } return nil } @@ -473,6 +505,8 @@ func (s *APIRPCServer) CreateTeam(args *CreateTeamArgs, returns *CreateTeamRetur CreateTeam(team *model.Team) (*model.Team, *model.AppError) }); ok { returns.A, returns.B = hook.CreateTeam(args.A) + } else { + return fmt.Errorf("API CreateTeam called but not implemented.") } return nil } @@ -499,6 +533,8 @@ func (s *APIRPCServer) DeleteTeam(args *DeleteTeamArgs, returns *DeleteTeamRetur DeleteTeam(teamId string) *model.AppError }); ok { returns.A = hook.DeleteTeam(args.A) + } else { + return fmt.Errorf("API DeleteTeam called but not implemented.") } return nil } @@ -526,6 +562,8 @@ func (s *APIRPCServer) GetTeam(args *GetTeamArgs, returns *GetTeamReturns) error GetTeam(teamId string) (*model.Team, *model.AppError) }); ok { returns.A, returns.B = hook.GetTeam(args.A) + } else { + return fmt.Errorf("API GetTeam called but not implemented.") } return nil } @@ -553,6 +591,8 @@ func (s *APIRPCServer) GetTeamByName(args *GetTeamByNameArgs, returns *GetTeamBy GetTeamByName(name string) (*model.Team, *model.AppError) }); ok { returns.A, returns.B = hook.GetTeamByName(args.A) + } else { + return fmt.Errorf("API GetTeamByName called but not implemented.") } return nil } @@ -580,6 +620,8 @@ func (s *APIRPCServer) UpdateTeam(args *UpdateTeamArgs, returns *UpdateTeamRetur UpdateTeam(team *model.Team) (*model.Team, *model.AppError) }); ok { returns.A, returns.B = hook.UpdateTeam(args.A) + } else { + return fmt.Errorf("API UpdateTeam called but not implemented.") } return nil } @@ -607,6 +649,8 @@ func (s *APIRPCServer) CreateChannel(args *CreateChannelArgs, returns *CreateCha CreateChannel(channel *model.Channel) (*model.Channel, *model.AppError) }); ok { returns.A, returns.B = hook.CreateChannel(args.A) + } else { + return fmt.Errorf("API CreateChannel called but not implemented.") } return nil } @@ -633,6 +677,8 @@ func (s *APIRPCServer) DeleteChannel(args *DeleteChannelArgs, returns *DeleteCha DeleteChannel(channelId string) *model.AppError }); ok { returns.A = hook.DeleteChannel(args.A) + } else { + return fmt.Errorf("API DeleteChannel called but not implemented.") } return nil } @@ -660,6 +706,8 @@ func (s *APIRPCServer) GetChannel(args *GetChannelArgs, returns *GetChannelRetur GetChannel(channelId string) (*model.Channel, *model.AppError) }); ok { returns.A, returns.B = hook.GetChannel(args.A) + } else { + return fmt.Errorf("API GetChannel called but not implemented.") } return nil } @@ -688,6 +736,8 @@ func (s *APIRPCServer) GetChannelByName(args *GetChannelByNameArgs, returns *Get GetChannelByName(name, teamId string) (*model.Channel, *model.AppError) }); ok { returns.A, returns.B = hook.GetChannelByName(args.A, args.B) + } else { + return fmt.Errorf("API GetChannelByName called but not implemented.") } return nil } @@ -716,6 +766,8 @@ func (s *APIRPCServer) GetDirectChannel(args *GetDirectChannelArgs, returns *Get GetDirectChannel(userId1, userId2 string) (*model.Channel, *model.AppError) }); ok { returns.A, returns.B = hook.GetDirectChannel(args.A, args.B) + } else { + return fmt.Errorf("API GetDirectChannel called but not implemented.") } return nil } @@ -743,6 +795,8 @@ func (s *APIRPCServer) GetGroupChannel(args *GetGroupChannelArgs, returns *GetGr GetGroupChannel(userIds []string) (*model.Channel, *model.AppError) }); ok { returns.A, returns.B = hook.GetGroupChannel(args.A) + } else { + return fmt.Errorf("API GetGroupChannel called but not implemented.") } return nil } @@ -770,6 +824,8 @@ func (s *APIRPCServer) UpdateChannel(args *UpdateChannelArgs, returns *UpdateCha UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) }); ok { returns.A, returns.B = hook.UpdateChannel(args.A) + } else { + return fmt.Errorf("API UpdateChannel called but not implemented.") } return nil } @@ -798,6 +854,8 @@ func (s *APIRPCServer) AddChannelMember(args *AddChannelMemberArgs, returns *Add AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) }); ok { returns.A, returns.B = hook.AddChannelMember(args.A, args.B) + } else { + return fmt.Errorf("API AddChannelMember called but not implemented.") } return nil } @@ -826,6 +884,8 @@ func (s *APIRPCServer) GetChannelMember(args *GetChannelMemberArgs, returns *Get GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) }); ok { returns.A, returns.B = hook.GetChannelMember(args.A, args.B) + } else { + return fmt.Errorf("API GetChannelMember called but not implemented.") } return nil } @@ -855,6 +915,8 @@ func (s *APIRPCServer) UpdateChannelMemberRoles(args *UpdateChannelMemberRolesAr UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError) }); ok { returns.A, returns.B = hook.UpdateChannelMemberRoles(args.A, args.B, args.C) + } else { + return fmt.Errorf("API UpdateChannelMemberRoles called but not implemented.") } return nil } @@ -884,6 +946,8 @@ func (s *APIRPCServer) UpdateChannelMemberNotifications(args *UpdateChannelMembe UpdateChannelMemberNotifications(channelId, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError) }); ok { returns.A, returns.B = hook.UpdateChannelMemberNotifications(args.A, args.B, args.C) + } else { + return fmt.Errorf("API UpdateChannelMemberNotifications called but not implemented.") } return nil } @@ -911,6 +975,8 @@ func (s *APIRPCServer) DeleteChannelMember(args *DeleteChannelMemberArgs, return DeleteChannelMember(channelId, userId string) *model.AppError }); ok { returns.A = hook.DeleteChannelMember(args.A, args.B) + } else { + return fmt.Errorf("API DeleteChannelMember called but not implemented.") } return nil } @@ -938,6 +1004,8 @@ func (s *APIRPCServer) CreatePost(args *CreatePostArgs, returns *CreatePostRetur CreatePost(post *model.Post) (*model.Post, *model.AppError) }); ok { returns.A, returns.B = hook.CreatePost(args.A) + } else { + return fmt.Errorf("API CreatePost called but not implemented.") } return nil } @@ -964,6 +1032,8 @@ func (s *APIRPCServer) DeletePost(args *DeletePostArgs, returns *DeletePostRetur DeletePost(postId string) *model.AppError }); ok { returns.A = hook.DeletePost(args.A) + } else { + return fmt.Errorf("API DeletePost called but not implemented.") } return nil } @@ -991,6 +1061,8 @@ func (s *APIRPCServer) GetPost(args *GetPostArgs, returns *GetPostReturns) error GetPost(postId string) (*model.Post, *model.AppError) }); ok { returns.A, returns.B = hook.GetPost(args.A) + } else { + return fmt.Errorf("API GetPost called but not implemented.") } return nil } @@ -1018,6 +1090,8 @@ func (s *APIRPCServer) UpdatePost(args *UpdatePostArgs, returns *UpdatePostRetur UpdatePost(post *model.Post) (*model.Post, *model.AppError) }); ok { returns.A, returns.B = hook.UpdatePost(args.A) + } else { + return fmt.Errorf("API UpdatePost called but not implemented.") } return nil } @@ -1045,6 +1119,8 @@ func (s *APIRPCServer) KVSet(args *KVSetArgs, returns *KVSetReturns) error { KVSet(key string, value []byte) *model.AppError }); ok { returns.A = hook.KVSet(args.A, args.B) + } else { + return fmt.Errorf("API KVSet called but not implemented.") } return nil } @@ -1072,6 +1148,8 @@ func (s *APIRPCServer) KVGet(args *KVGetArgs, returns *KVGetReturns) error { KVGet(key string) ([]byte, *model.AppError) }); ok { returns.A, returns.B = hook.KVGet(args.A) + } else { + return fmt.Errorf("API KVGet called but not implemented.") } return nil } @@ -1098,6 +1176,8 @@ func (s *APIRPCServer) KVDelete(args *KVDeleteArgs, returns *KVDeleteReturns) er KVDelete(key string) *model.AppError }); ok { returns.A = hook.KVDelete(args.A) + } else { + return fmt.Errorf("API KVDelete called but not implemented.") } return nil } @@ -1125,6 +1205,120 @@ func (s *APIRPCServer) PublishWebSocketEvent(args *PublishWebSocketEventArgs, re PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *model.WebsocketBroadcast) }); ok { hook.PublishWebSocketEvent(args.A, args.B, args.C) + } else { + return fmt.Errorf("API PublishWebSocketEvent called but not implemented.") + } + return nil +} + +type LogDebugArgs struct { + A string + B []interface{} +} + +type LogDebugReturns struct { +} + +func (g *APIRPCClient) LogDebug(msg string, keyValuePairs ...interface{}) { + _args := &LogDebugArgs{msg, keyValuePairs} + _returns := &LogDebugReturns{} + if err := g.client.Call("Plugin.LogDebug", _args, _returns); err != nil { + g.log.Error("RPC call to LogDebug API failed.", mlog.Err(err)) + } + return +} + +func (s *APIRPCServer) LogDebug(args *LogDebugArgs, returns *LogDebugReturns) error { + if hook, ok := s.impl.(interface { + LogDebug(msg string, keyValuePairs ...interface{}) + }); ok { + hook.LogDebug(args.A, args.B...) + } else { + return fmt.Errorf("API LogDebug called but not implemented.") + } + return nil +} + +type LogInfoArgs struct { + A string + B []interface{} +} + +type LogInfoReturns struct { +} + +func (g *APIRPCClient) LogInfo(msg string, keyValuePairs ...interface{}) { + _args := &LogInfoArgs{msg, keyValuePairs} + _returns := &LogInfoReturns{} + if err := g.client.Call("Plugin.LogInfo", _args, _returns); err != nil { + g.log.Error("RPC call to LogInfo API failed.", mlog.Err(err)) + } + return +} + +func (s *APIRPCServer) LogInfo(args *LogInfoArgs, returns *LogInfoReturns) error { + if hook, ok := s.impl.(interface { + LogInfo(msg string, keyValuePairs ...interface{}) + }); ok { + hook.LogInfo(args.A, args.B...) + } else { + return fmt.Errorf("API LogInfo called but not implemented.") + } + return nil +} + +type LogErrorArgs struct { + A string + B []interface{} +} + +type LogErrorReturns struct { +} + +func (g *APIRPCClient) LogError(msg string, keyValuePairs ...interface{}) { + _args := &LogErrorArgs{msg, keyValuePairs} + _returns := &LogErrorReturns{} + if err := g.client.Call("Plugin.LogError", _args, _returns); err != nil { + g.log.Error("RPC call to LogError API failed.", mlog.Err(err)) + } + return +} + +func (s *APIRPCServer) LogError(args *LogErrorArgs, returns *LogErrorReturns) error { + if hook, ok := s.impl.(interface { + LogError(msg string, keyValuePairs ...interface{}) + }); ok { + hook.LogError(args.A, args.B...) + } else { + return fmt.Errorf("API LogError called but not implemented.") + } + return nil +} + +type LogWarnArgs struct { + A string + B []interface{} +} + +type LogWarnReturns struct { +} + +func (g *APIRPCClient) LogWarn(msg string, keyValuePairs ...interface{}) { + _args := &LogWarnArgs{msg, keyValuePairs} + _returns := &LogWarnReturns{} + if err := g.client.Call("Plugin.LogWarn", _args, _returns); err != nil { + g.log.Error("RPC call to LogWarn API failed.", mlog.Err(err)) + } + return +} + +func (s *APIRPCServer) LogWarn(args *LogWarnArgs, returns *LogWarnReturns) error { + if hook, ok := s.impl.(interface { + LogWarn(msg string, keyValuePairs ...interface{}) + }); ok { + hook.LogWarn(args.A, args.B...) + } else { + return fmt.Errorf("API LogWarn called but not implemented.") } return nil } diff --git a/plugin/hclog_adapter.go b/plugin/hclog_adapter.go index c8e39877e..55d60f508 100644 --- a/plugin/hclog_adapter.go +++ b/plugin/hclog_adapter.go @@ -6,6 +6,7 @@ package plugin import ( "fmt" "log" + "strings" "github.com/hashicorp/go-hclog" "github.com/mattermost/mattermost-server/mlog" @@ -17,23 +18,48 @@ type HclogAdapter struct { } func (h *HclogAdapter) Trace(msg string, args ...interface{}) { - h.wrappedLogger.Debug(msg, mlog.String(h.extrasKey, fmt.Sprintln(args...))) + extras := strings.TrimSpace(fmt.Sprint(args...)) + if extras != "" { + h.wrappedLogger.Debug(msg, mlog.String(h.extrasKey, extras)) + } else { + h.wrappedLogger.Debug(msg) + } } func (h *HclogAdapter) Debug(msg string, args ...interface{}) { - h.wrappedLogger.Debug(msg, mlog.String(h.extrasKey, fmt.Sprintln(args...))) + extras := strings.TrimSpace(fmt.Sprint(args...)) + if extras != "" { + h.wrappedLogger.Debug(msg, mlog.String(h.extrasKey, extras)) + } else { + h.wrappedLogger.Debug(msg) + } } func (h *HclogAdapter) Info(msg string, args ...interface{}) { - h.wrappedLogger.Info(msg, mlog.String(h.extrasKey, fmt.Sprintln(args...))) + extras := strings.TrimSpace(fmt.Sprint(args...)) + if extras != "" { + h.wrappedLogger.Info(msg, mlog.String(h.extrasKey, extras)) + } else { + h.wrappedLogger.Info(msg) + } } func (h *HclogAdapter) Warn(msg string, args ...interface{}) { - h.wrappedLogger.Warn(msg, mlog.String(h.extrasKey, fmt.Sprintln(args...))) + extras := strings.TrimSpace(fmt.Sprint(args...)) + if extras != "" { + h.wrappedLogger.Warn(msg, mlog.String(h.extrasKey, extras)) + } else { + h.wrappedLogger.Warn(msg) + } } func (h *HclogAdapter) Error(msg string, args ...interface{}) { - h.wrappedLogger.Error(msg, mlog.String(h.extrasKey, fmt.Sprintln(args...))) + extras := strings.TrimSpace(fmt.Sprint(args...)) + if extras != "" { + h.wrappedLogger.Error(msg, mlog.String(h.extrasKey, extras)) + } else { + h.wrappedLogger.Error(msg) + } } func (h *HclogAdapter) IsTrace() bool { diff --git a/plugin/interface_generator/main.go b/plugin/interface_generator/main.go index 5f66506d3..8cbaf4249 100644 --- a/plugin/interface_generator/main.go +++ b/plugin/interface_generator/main.go @@ -76,12 +76,22 @@ func FieldListDestruct(structPrefix string, fieldList *ast.FieldList, fileset *t } nextLetter := 'A' for _, field := range fieldList.List { + typeNameBuffer := &bytes.Buffer{} + err := printer.Fprint(typeNameBuffer, fileset, field.Type) + if err != nil { + panic(err) + } + typeName := typeNameBuffer.String() + suffix := "" + if strings.HasPrefix(typeName, "...") { + suffix = "..." + } if len(field.Names) == 0 { - result = append(result, structPrefix+string(nextLetter)) + result = append(result, structPrefix+string(nextLetter)+suffix) nextLetter += 1 } else { for range field.Names { - result = append(result, structPrefix+string(nextLetter)) + result = append(result, structPrefix+string(nextLetter)+suffix) nextLetter += 1 } } @@ -103,6 +113,9 @@ func FieldListToStructList(fieldList *ast.FieldList, fileset *token.FileSet) str panic(err) } typeName := typeNameBuffer.String() + if strings.HasPrefix(typeName, "...") { + typeName = strings.Replace(typeName, "...", "[]", 1) + } if len(field.Names) == 0 { result = append(result, string(nextLetter)+" "+typeName) nextLetter += 1 @@ -224,6 +237,8 @@ func (s *HooksRPCServer) {{.Name}}(args *{{.Name}}Args, returns *{{.Name}}Return {{.Name}}{{funcStyle .Params}} {{funcStyle .Return}} }); ok { {{if .Return}}{{destruct "returns." .Return}} = {{end}}hook.{{.Name}}({{destruct "args." .Params}}) + } else { + return fmt.Errorf("Hook {{.Name}} called but not implemented.") } return nil } @@ -253,6 +268,8 @@ func (s *APIRPCServer) {{.Name}}(args *{{.Name}}Args, returns *{{.Name}}Returns) {{.Name}}{{funcStyle .Params}} {{funcStyle .Return}} }); ok { {{if .Return}}{{destruct "returns." .Return}} = {{end}}hook.{{.Name}}({{destruct "args." .Params}}) + } else { + return fmt.Errorf("API {{.Name}} called but not implemented.") } return nil } diff --git a/plugin/plugintest/api.go b/plugin/plugintest/api.go index 145fcbf9d..b9d8d7521 100644 --- a/plugin/plugintest/api.go +++ b/plugin/plugintest/api.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make plugin-mocks`. @@ -563,6 +563,38 @@ func (_m *API) LoadPluginConfiguration(dest interface{}) error { return r0 } +// LogDebug provides a mock function with given fields: msg, keyValuePairs +func (_m *API) LogDebug(msg string, keyValuePairs ...interface{}) { + var _ca []interface{} + _ca = append(_ca, msg) + _ca = append(_ca, keyValuePairs...) + _m.Called(_ca...) +} + +// LogError provides a mock function with given fields: msg, keyValuePairs +func (_m *API) LogError(msg string, keyValuePairs ...interface{}) { + var _ca []interface{} + _ca = append(_ca, msg) + _ca = append(_ca, keyValuePairs...) + _m.Called(_ca...) +} + +// LogInfo provides a mock function with given fields: msg, keyValuePairs +func (_m *API) LogInfo(msg string, keyValuePairs ...interface{}) { + var _ca []interface{} + _ca = append(_ca, msg) + _ca = append(_ca, keyValuePairs...) + _m.Called(_ca...) +} + +// LogWarn provides a mock function with given fields: msg, keyValuePairs +func (_m *API) LogWarn(msg string, keyValuePairs ...interface{}) { + var _ca []interface{} + _ca = append(_ca, msg) + _ca = append(_ca, keyValuePairs...) + _m.Called(_ca...) +} + // PublishWebSocketEvent provides a mock function with given fields: event, payload, broadcast func (_m *API) PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *model.WebsocketBroadcast) { _m.Called(event, payload, broadcast) diff --git a/plugin/plugintest/hooks.go b/plugin/plugintest/hooks.go index 0d335a626..790a5a993 100644 --- a/plugin/plugintest/hooks.go +++ b/plugin/plugintest/hooks.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make plugin-mocks`. diff --git a/plugin/supervisor.go b/plugin/supervisor.go index 0471f7861..58a7aa783 100644 --- a/plugin/supervisor.go +++ b/plugin/supervisor.go @@ -5,7 +5,6 @@ package plugin import ( "fmt" - "os" "os/exec" "path/filepath" "strings" @@ -29,7 +28,7 @@ func NewSupervisor(pluginInfo *model.BundleInfo, parentLogger *mlog.Logger, apiI wrappedLogger := pluginInfo.WrapLogger(parentLogger) hclogAdaptedLogger := &HclogAdapter{ - wrappedLogger: wrappedLogger, + wrappedLogger: wrappedLogger.WithCallerSkip(1), extrasKey: "wrapped_extras", } @@ -50,8 +49,8 @@ func NewSupervisor(pluginInfo *model.BundleInfo, parentLogger *mlog.Logger, apiI HandshakeConfig: Handshake, Plugins: pluginMap, Cmd: exec.Command(executable), - SyncStdout: os.Stdout, - SyncStderr: os.Stdout, + SyncStdout: wrappedLogger.With(mlog.String("source", "plugin_stdout")).StdLogWriter(), + SyncStderr: wrappedLogger.With(mlog.String("source", "plugin_stderr")).StdLogWriter(), Logger: hclogAdaptedLogger, StartTimeout: time.Second * 3, }) -- cgit v1.2.3-1-g7c22