From 303cc5b7b1eaf1777e2cb69e78e8ab8b090b3432 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 14:22:04 +0000 Subject: [PATCH 1/3] Initial plan From 66b61ba8f103d683c82eba69c126d5edf0d85c9f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 14:26:30 +0000 Subject: [PATCH 2/3] Implement DefaultLogger following Logger interface - Created default_logger.go with DefaultLogger struct - Implemented all Logger interface methods (SetEventTypes, OnBeforeEvent, OnAfterEvent, SetLogCallback) - Added SetOutput method to support buffer/console output - Set StartTime in OnBeforeEvent and calculate Duration in OnAfterEvent - Filter events using LogEntry.IsActive based on SetEventTypes - Call user callback at end of OnAfterEvent if set - Use 2026 copyright header as requested Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- log/default_logger.go | 137 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 log/default_logger.go diff --git a/log/default_logger.go b/log/default_logger.go new file mode 100644 index 00000000..8b491f65 --- /dev/null +++ b/log/default_logger.go @@ -0,0 +1,137 @@ +// Copyright 2026 The casbin Authors. All Rights Reserved. +// +// 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 log + +import ( + "fmt" + "io" + "os" + "time" +) + +// DefaultLogger is the default implementation of the Logger interface. +type DefaultLogger struct { + output io.Writer + eventTypes map[EventType]bool + logCallback func(entry *LogEntry) error +} + +// NewDefaultLogger creates a new DefaultLogger instance. +// If no output is set via SetOutput, it defaults to os.Stdout. +func NewDefaultLogger() *DefaultLogger { + return &DefaultLogger{ + output: os.Stdout, + eventTypes: make(map[EventType]bool), + } +} + +// SetOutput sets the output destination for the logger. +// It can be set to a buffer or any io.Writer. +func (l *DefaultLogger) SetOutput(w io.Writer) { + if w != nil { + l.output = w + } +} + +// SetEventTypes sets the event types that should be logged. +// Only events matching these types will have IsActive set to true. +func (l *DefaultLogger) SetEventTypes(eventTypes []EventType) error { + l.eventTypes = make(map[EventType]bool) + for _, et := range eventTypes { + l.eventTypes[et] = true + } + return nil +} + +// OnBeforeEvent is called before an event occurs. +// It sets the StartTime and determines if the event should be active based on configured event types. +func (l *DefaultLogger) OnBeforeEvent(entry *LogEntry) error { + if entry == nil { + return fmt.Errorf("log entry is nil") + } + + entry.StartTime = time.Now() + + // Set IsActive based on whether this event type is enabled + // If no event types are configured, all events are considered active + if len(l.eventTypes) == 0 { + entry.IsActive = true + } else { + entry.IsActive = l.eventTypes[entry.EventType] + } + + return nil +} + +// OnAfterEvent is called after an event completes. +// It calculates the duration, logs the entry if active, and calls the user callback if set. +func (l *DefaultLogger) OnAfterEvent(entry *LogEntry) error { + if entry == nil { + return fmt.Errorf("log entry is nil") + } + + entry.EndTime = time.Now() + entry.Duration = entry.EndTime.Sub(entry.StartTime) + + // Only log if the event is active + if entry.IsActive && l.output != nil { + if err := l.writeLog(entry); err != nil { + return err + } + } + + // Call user-provided callback if set + if l.logCallback != nil { + if err := l.logCallback(entry); err != nil { + return err + } + } + + return nil +} + +// SetLogCallback sets a user-provided callback function. +// The callback is called at the end of OnAfterEvent. +func (l *DefaultLogger) SetLogCallback(callback func(entry *LogEntry) error) error { + l.logCallback = callback + return nil +} + +// writeLog writes the log entry to the configured output. +func (l *DefaultLogger) writeLog(entry *LogEntry) error { + var logMessage string + + switch entry.EventType { + case EventEnforce: + logMessage = fmt.Sprintf("[%s] Enforce: subject=%s, object=%s, action=%s, domain=%s, allowed=%v, duration=%v\n", + entry.EventType, entry.Subject, entry.Object, entry.Action, entry.Domain, entry.Allowed, entry.Duration) + case EventAddPolicy, EventRemovePolicy: + logMessage = fmt.Sprintf("[%s] RuleCount=%d, duration=%v\n", + entry.EventType, entry.RuleCount, entry.Duration) + case EventLoadPolicy, EventSavePolicy: + logMessage = fmt.Sprintf("[%s] RuleCount=%d, duration=%v\n", + entry.EventType, entry.RuleCount, entry.Duration) + default: + logMessage = fmt.Sprintf("[%s] duration=%v\n", + entry.EventType, entry.Duration) + } + + if entry.Error != nil { + logMessage = fmt.Sprintf("%s Error: %v\n", logMessage[:len(logMessage)-1], entry.Error) + } + + _, err := l.output.Write([]byte(logMessage)) + return err +} From 9f52da71fbd2aec755cb20166bc504ae9a119ca1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 14:29:46 +0000 Subject: [PATCH 3/3] Fix string slicing issue in writeLog method Use strings.TrimSuffix instead of direct string slicing to safely remove newline when adding error message Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- log/default_logger.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/log/default_logger.go b/log/default_logger.go index 8b491f65..13ec21d9 100644 --- a/log/default_logger.go +++ b/log/default_logger.go @@ -18,6 +18,7 @@ import ( "fmt" "io" "os" + "strings" "time" ) @@ -129,7 +130,8 @@ func (l *DefaultLogger) writeLog(entry *LogEntry) error { } if entry.Error != nil { - logMessage = fmt.Sprintf("%s Error: %v\n", logMessage[:len(logMessage)-1], entry.Error) + logMessage = strings.TrimSuffix(logMessage, "\n") + logMessage = fmt.Sprintf("%s Error: %v\n", logMessage, entry.Error) } _, err := l.output.Write([]byte(logMessage))