• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-server / 1900805255

01 Jul 2025 05:31PM UTC coverage: 66.222% (+0.5%) from 65.694%
1900805255

Pull #774

gitlab-ci

web-flow
chore: bump pillow from 11.2.1 to 11.3.0 in /backend/tests

Bumps [pillow](https://github.com/python-pillow/Pillow) from 11.2.1 to 11.3.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/11.2.1...11.3.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-version: 11.3.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #774: chore: bump pillow from 11.2.1 to 11.3.0 in /backend/tests

29486 of 44526 relevant lines covered (66.22%)

1.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.44
/backend/pkg/accesslog/middleware_gin.go
1
// Copyright 2024 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
package accesslog
16

17
import (
18
        "context"
19
        "fmt"
20
        "net"
21
        "net/http"
22
        "strings"
23
        "time"
24

25
        "github.com/gin-gonic/gin"
26
        "github.com/pkg/errors"
27
        "github.com/sirupsen/logrus"
28

29
        "github.com/mendersoftware/mender-server/pkg/log"
30
        "github.com/mendersoftware/mender-server/pkg/rest.utils"
31
)
32

33
type AccessLogger struct {
34
        DisableLog   func(c *gin.Context) bool
35
        ClientIPHook func(r *http.Request) net.IP
36
}
37

38
func formatPathParams(params gin.Params) string {
7✔
39
        var b strings.Builder
7✔
40
        lastIdx := len(params) - 1
7✔
41
        delimiter := " "
7✔
42
        for i, p := range params {
14✔
43
                if i == lastIdx {
14✔
44
                        delimiter = ""
7✔
45
                }
7✔
46
                key := strings.TrimPrefix(p.Key, ":")
7✔
47
                fmt.Fprintf(&b, "%s=%s%s", key, p.Value, delimiter)
7✔
48
        }
49
        return b.String()
7✔
50
}
51

52
func (a AccessLogger) LogFunc(
53
        ctx context.Context,
54
        c *gin.Context,
55
        startTime time.Time,
56
) {
7✔
57
        logCtx := logrus.Fields{
7✔
58
                "method":      c.Request.Method,
7✔
59
                "path":        c.FullPath(),
7✔
60
                "path_params": formatPathParams(c.Params),
7✔
61
                "qs":          c.Request.URL.RawQuery,
7✔
62
                "ts": startTime.
7✔
63
                        Truncate(time.Millisecond).
7✔
64
                        Format(time.RFC3339Nano),
7✔
65
                "type":      c.Request.Proto,
7✔
66
                "useragent": c.Request.UserAgent(),
7✔
67
        }
7✔
68
        if a.ClientIPHook != nil {
7✔
69
                logCtx["clientip"] = a.ClientIPHook(c.Request)
×
70
        }
×
71
        lc := fromContext(ctx)
7✔
72
        if lc != nil {
14✔
73
                lc.addFields(logCtx)
7✔
74
        }
7✔
75
        if r := recover(); r != nil {
7✔
76
                trace := collectTrace()
×
77
                logCtx["trace"] = trace
×
78
                logCtx["panic"] = r
×
79

×
80
                func() {
×
81
                        // Try to respond with an internal server error.
×
82
                        // If the connection is broken it might panic again.
×
83
                        defer func() { recover() }() // nolint:errcheck
×
84
                        rest.RenderError(c,
×
85
                                http.StatusInternalServerError,
×
86
                                errors.New("internal error"),
×
87
                        )
×
88
                }()
89
        } else if a.DisableLog != nil && a.DisableLog(c) {
8✔
90
                return
1✔
91
        }
1✔
92
        latency := time.Since(startTime)
7✔
93
        // We do not need more than 3 digit fraction
7✔
94
        if latency > time.Second {
9✔
95
                latency = latency.Round(time.Millisecond)
2✔
96
        } else if latency > time.Millisecond {
16✔
97
                latency = latency.Round(time.Microsecond)
7✔
98
        }
7✔
99
        code := c.Writer.Status()
7✔
100
        select {
7✔
101
        case <-ctx.Done():
×
102
                if errors.Is(ctx.Err(), context.Canceled) {
×
103
                        code = StatusClientClosedConnection
×
104
                }
×
105
        default:
7✔
106
        }
107
        logCtx["responsetime"] = latency.String()
7✔
108
        logCtx["status"] = c.Writer.Status()
7✔
109
        logCtx["byteswritten"] = c.Writer.Size()
7✔
110

7✔
111
        var logLevel logrus.Level = logrus.InfoLevel
7✔
112
        if code >= 500 {
8✔
113
                logLevel = logrus.ErrorLevel
1✔
114
        } else if code >= 400 {
14✔
115
                logLevel = logrus.WarnLevel
6✔
116
        }
6✔
117
        if len(c.Errors) > 0 {
12✔
118
                errs := c.Errors.Errors()
5✔
119
                var errMsg string
5✔
120
                if len(errs) == 1 {
10✔
121
                        errMsg = errs[0]
5✔
122
                } else {
6✔
123
                        for i, err := range errs {
2✔
124
                                errMsg = errMsg + fmt.Sprintf(
1✔
125
                                        "#%02d: %s\n", i+1, err,
1✔
126
                                )
1✔
127
                        }
1✔
128
                }
129
                logCtx["error"] = errMsg
5✔
130
        }
131
        log.FromContext(c.Request.Context()).
7✔
132
                WithFields(logCtx).
7✔
133
                Log(logLevel)
7✔
134
}
135

136
// Middleware implementsa gin compatible MiddlewareFunc
137
//
138
// NOTE: This accesslog middleware also implements the legacy requestlog
139
// middleware.
140
func (a AccessLogger) Middleware(c *gin.Context) {
7✔
141
        ctx := c.Request.Context()
7✔
142
        startTime := time.Now()
7✔
143
        ctx = log.WithContext(ctx, log.New(log.Ctx{}))
7✔
144
        ctx = withContext(ctx, &logContext{maxErrors: DefaultMaxErrors})
7✔
145
        c.Request = c.Request.WithContext(ctx)
7✔
146
        defer a.LogFunc(ctx, c, startTime)
7✔
147
        c.Next()
7✔
148
}
7✔
149

150
// Middleware provides accesslog middleware for the gin-gonic framework.
151
// This middleware will recover any panic from occurring in the API
152
// handler and log it to error level with panic and trace showing the panic
153
// message and traceback respectively.
154
// If an error status is returned in the response, the middleware tries
155
// to pop the topmost error from the gin.Context (c.Error) and puts it in
156
// the "error" context to the final log entry.
157
func Middleware() gin.HandlerFunc {
7✔
158
        return AccessLogger{ClientIPHook: getClientIPFromEnv()}.Middleware
7✔
159
}
7✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc