Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

cnlangzi
Copy link
Member

@cnlangzi cnlangzi commented Feb 11, 2025

Changed

Fixed

Added

Tests

Tasks to complete before merging PR:

  • Ensure unit tests are passing. If not run make unit-test to check for any regressions 📋
  • Ensure lint tests are passing. if not run make lint to check for any issues
  • Ensure codecov/patch is passing for changes.

Summary by Sourcery

Add request logging middleware to log incoming requests, and instructions for using GoAccess to generate and serve real-time analysis reports.

New Features:

  • Added reqlog middleware to log incoming requests with customizable format (default: Combined Log Format).
  • Added real-time request reporting using GoAccess.

Tests:

  • Added unit tests for the reqlog middleware.

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 11, 2025

Reviewer's Guide by Sourcery

This pull request introduces a new request logging middleware 'reqlog' along with comprehensive documentation and tests. The changes implement a middleware that logs each incoming request using configurable formatting options, enhance the response writer to track body bytes sent, and add tests to ensure correct behavior.

Sequence diagram for logging middleware request flow

sequenceDiagram
    actor Client
    participant Middleware as RequestLogMiddleware
    participant Handler as NextHandler
    participant Logger as LogInstance

    Client->>Middleware: HTTP Request starts
    Middleware->>Handler: Invoke next(c)
    Handler-->>Middleware: Return response
    Middleware->>Logger: Log request details (Combined format)
    Middleware->>Client: Send Response
Loading

Class diagram for request logging middleware

classDiagram
    %% Define the Options structure
    class Options {
      +*log.Logger Logger
      +func(*xun.Context) string GetVisitor
      +func(*xun.Context) string GetUser
      +Format Format
    }

    %% Define reqlog middleware and functions
    class ReqlogMiddleware {
      +New(...Option) xun.Middleware
    }

    %% Option functions
    class WithLogger {
      +WithLogger(l *log.Logger) Option
    }
    class WithVisitor {
      +WithVisitor(func(c *xun.Context) string) Option
    }
    class WithUser {
      +WithUser(func(c *xun.Context) string) Option
    }
    class WithFormat {
      +WithFormat(f Format) Option
    }

    %% Format functions
    class Combined {
      +Combined(c *xun.Context, options *Options, starts time.Time)
    }
    class Common {
      +Common(c *xun.Context, options *Options, starts time.Time)
    }

    %% Relationships
    ReqlogMiddleware ..> Options : uses
    Options <|-- WithLogger
    Options <|-- WithVisitor
    Options <|-- WithUser
    Options <|-- WithFormat

    ReqlogMiddleware ..> Combined : logs using
    ReqlogMiddleware ..> Common : alternative format
Loading

File-Level Changes

Change Details Files
Added detailed documentation for request logging middleware
  • Included a new 'Request Logging' section in the README with usage instructions and examples
  • Provided sample code to setup logger and middleware usage
  • Added instructions and commands to install and run GoAccess for real-time log analysis
  • Documented API usage with code snippets showing middleware integration and route handling for report serving
README.md
Enhanced response writer to track response byte counts
  • Modified the stdResponseWriter to accumulate body sent bytes in its Write method
  • Updated the deflateResponseWriter and gzipResponseWriter to count body bytes during write operations
  • Extended the ResponseWriter interface to include a new method for retrieving body bytes sent
response_writer_std.go
response_writer_deflate.go
response_writer_gzip.go
response_writer.go
Implemented the reqlog logging middleware with configurable options and tests
  • Introduced a new middleware that logs requests using customizable format options (Combined and Common)
  • Created configuration options using functions like WithLogger, WithVisitor, WithUser, and WithFormat
  • Added tests in a dedicated log_test file to validate the middleware logging behavior and format outputs
  • Provided support files (format and option) to modularize middleware configuration and formatting
ext/reqlog/log.go
ext/reqlog/option.go
ext/reqlog/format.go
ext/reqlog/log_test.go

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @cnlangzi - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a benchmark to evaluate the performance impact of the logging middleware.
  • It might be helpful to provide an example of how to use the middleware with a custom log format.
Here's what I looked at during the review
  • 🟡 General issues: 2 issues found
  • 🟢 Security: all looks good
  • 🟡 Testing: 1 issue found
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

// Combined log request with Combined Log Format (XLF/ELF)
func Combined(c *xun.Context, options *Options, starts time.Time) {
requestLine := fmt.Sprintf(`"%s %s %s"`, c.Request.Method, c.Request.URL.Path, c.Request.Proto)
host, _, _ := net.SplitHostPort(c.Request.RemoteAddr)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Consider error handling in host extraction.

While it's likely that RemoteAddr is well-formed, ignoring the error from net.SplitHostPort might lead to unexpected values in logs. A brief comment or error handling may improve robustness.

Suggested change
host, _, _ := net.SplitHostPort(c.Request.RemoteAddr)
host, _, err := net.SplitHostPort(c.Request.RemoteAddr)
if err != nil {
// fallback to full remote address if unable to split host and port
host = c.Request.RemoteAddr
}

@@ -0,0 +1,86 @@
package reqlog
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Test cases for error scenarios are missing.

It would be beneficial to add tests to cover cases where the logger fails to write, or when the request context is missing expected values. This ensures the middleware handles errors gracefully and doesn't cause unexpected behavior.

Suggested implementation:

import (
	"bytes"
	"errors"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/yaitoo/xun"
)
type errorWriter struct{}

func (ew errorWriter) Write(p []byte) (int, error) {
	return 0, errors.New("write error")
}
func TestLoggerWriteError(t *testing.T) {
	// Create a logger that uses a writer which always returns an error.
	ew := errorWriter{}
	logger := log.New(ew, "", 0)

	req := httptest.NewRequest("GET", "http://example.com", nil)
	recorder := httptest.NewRecorder()

	// Dummy handler to simulate the next middleware/handler.
	next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	// Assuming RequestLoggingHandler is our middleware function that accepts a logger.
	handler := RequestLoggingHandler(next, logger)
	handler.ServeHTTP(recorder, req)

	// Even if the logger write fails, the middleware should allow the request to complete.
	require.Equal(t, http.StatusOK, recorder.Code)
}

func TestMissingExpectedRequestContext(t *testing.T) {
	// Create a request without the expected context values.
	req := httptest.NewRequest("GET", "http://example.com", nil)
	recorder := httptest.NewRecorder()

	// Dummy handler for the next stage.
	next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	// Using the standard logger.
	handler := RequestLoggingHandler(next, log.Default())
	handler.ServeHTTP(recorder, req)

	// The middleware should handle the missing context gracefully and proceed.
	require.Equal(t, http.StatusOK, recorder.Code)
}

Make sure that the middleware function RequestLoggingHandler(next http.Handler, logger *log.Logger) is defined in your codebase so that these tests can be compiled and executed. You might need to adjust the function signature or its usage to match your project's actual implementation details.

@codecov
Copy link

codecov bot commented Feb 11, 2025

Codecov Report

Attention: Patch coverage is 96.77419% with 3 lines in your changes missing coverage. Please review.

Project coverage is 92.69%. Comparing base (9c23fef) to head (b5cb67c).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
response_writer_std.go 77.77% 2 Missing ⚠️
ext/reqlog/option.go 96.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #45      +/-   ##
==========================================
+ Coverage   92.47%   92.69%   +0.21%     
==========================================
  Files          43       46       +3     
  Lines        1675     1766      +91     
==========================================
+ Hits         1549     1637      +88     
- Misses         93       96       +3     
  Partials       33       33              
Flag Coverage Δ
Unit-Tests 92.69% <96.77%> (+0.21%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@cnlangzi cnlangzi changed the title feat(reqlog): added logging middleware to logging requests feat(reqlog): added a middleware to logging requests Feb 12, 2025
@cnlangzi cnlangzi merged commit d41aa17 into main Feb 12, 2025
6 of 7 checks passed
@cnlangzi cnlangzi deleted the feat/reqlog branch February 12, 2025 00:08
@deepsource-io
Copy link

deepsource-io bot commented Feb 12, 2025

Here's the code health analysis summary for commits 9c23fef..b5cb67c. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource Go LogoGo❌ FailureView Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant