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

mendersoftware / mender-server / 1821438718

16 May 2025 02:19PM UTC coverage: 66.309% (+0.5%) from 65.853%
1821438718

Pull #674

gitlab-ci

mzedel
fix(gui): prevented device tag editor to be shown when no tags exist

- this is to reduce confusion about tags defined async to the current session not being visible

Ticket: ME-528
Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #674: ME-529, ME-528 - adjustments to device tag editing

29542 of 44552 relevant lines covered (66.31%)

1.45 hits per line

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

75.29
/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
        "time"
23

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

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

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

37
func (a AccessLogger) LogFunc(
38
        ctx context.Context,
39
        c *gin.Context,
40
        startTime time.Time,
41
) {
4✔
42
        logCtx := logrus.Fields{
4✔
43
                "method": c.Request.Method,
4✔
44
                "path":   c.Request.URL.Path,
4✔
45
                "qs":     c.Request.URL.RawQuery,
4✔
46
                "ts": startTime.
4✔
47
                        Truncate(time.Millisecond).
4✔
48
                        Format(time.RFC3339Nano),
4✔
49
                "type":      c.Request.Proto,
4✔
50
                "useragent": c.Request.UserAgent(),
4✔
51
        }
4✔
52
        if a.ClientIPHook != nil {
4✔
53
                logCtx["clientip"] = a.ClientIPHook(c.Request)
×
54
        }
×
55
        lc := fromContext(ctx)
4✔
56
        if lc != nil {
8✔
57
                lc.addFields(logCtx)
4✔
58
        }
4✔
59
        if r := recover(); r != nil {
4✔
60
                trace := collectTrace()
×
61
                logCtx["trace"] = trace
×
62
                logCtx["panic"] = r
×
63

×
64
                func() {
×
65
                        // Try to respond with an internal server error.
×
66
                        // If the connection is broken it might panic again.
×
67
                        defer func() { recover() }() // nolint:errcheck
×
68
                        rest.RenderError(c,
×
69
                                http.StatusInternalServerError,
×
70
                                errors.New("internal error"),
×
71
                        )
×
72
                }()
73
        } else if a.DisableLog != nil && a.DisableLog(c) {
4✔
74
                return
×
75
        }
×
76
        latency := time.Since(startTime)
4✔
77
        // We do not need more than 3 digit fraction
4✔
78
        if latency > time.Second {
5✔
79
                latency = latency.Round(time.Millisecond)
1✔
80
        } else if latency > time.Millisecond {
8✔
81
                latency = latency.Round(time.Microsecond)
3✔
82
        }
3✔
83
        code := c.Writer.Status()
4✔
84
        select {
4✔
85
        case <-ctx.Done():
×
86
                if errors.Is(ctx.Err(), context.Canceled) {
×
87
                        code = StatusClientClosedConnection
×
88
                }
×
89
        default:
4✔
90
        }
91
        logCtx["responsetime"] = latency.String()
4✔
92
        logCtx["status"] = c.Writer.Status()
4✔
93
        logCtx["byteswritten"] = c.Writer.Size()
4✔
94

4✔
95
        var logLevel logrus.Level = logrus.InfoLevel
4✔
96
        if code >= 500 {
4✔
97
                logLevel = logrus.ErrorLevel
×
98
        } else if code >= 400 {
7✔
99
                logLevel = logrus.WarnLevel
3✔
100
        }
3✔
101
        if len(c.Errors) > 0 {
6✔
102
                errs := c.Errors.Errors()
2✔
103
                var errMsg string
2✔
104
                if len(errs) == 1 {
4✔
105
                        errMsg = errs[0]
2✔
106
                } else {
3✔
107
                        for i, err := range errs {
2✔
108
                                errMsg = errMsg + fmt.Sprintf(
1✔
109
                                        "#%02d: %s\n", i+1, err,
1✔
110
                                )
1✔
111
                        }
1✔
112
                }
113
                logCtx["error"] = errMsg
2✔
114
        }
115
        log.FromContext(c.Request.Context()).
4✔
116
                WithFields(logCtx).
4✔
117
                Log(logLevel)
4✔
118
}
119

120
// Middleware implementsa gin compatible MiddlewareFunc
121
//
122
// NOTE: This accesslog middleware also implements the legacy requestlog
123
// middleware.
124
func (a AccessLogger) Middleware(c *gin.Context) {
4✔
125
        ctx := c.Request.Context()
4✔
126
        startTime := time.Now()
4✔
127
        ctx = log.WithContext(ctx, log.New(log.Ctx{}))
4✔
128
        ctx = withContext(ctx, &logContext{maxErrors: DefaultMaxErrors})
4✔
129
        c.Request = c.Request.WithContext(ctx)
4✔
130
        defer a.LogFunc(ctx, c, startTime)
4✔
131
        c.Next()
4✔
132
}
4✔
133

134
// Middleware provides accesslog middleware for the gin-gonic framework.
135
// This middleware will recover any panic from occurring in the API
136
// handler and log it to error level with panic and trace showing the panic
137
// message and traceback respectively.
138
// If an error status is returned in the response, the middleware tries
139
// to pop the topmost error from the gin.Context (c.Error) and puts it in
140
// the "error" context to the final log entry.
141
func Middleware() gin.HandlerFunc {
4✔
142
        return AccessLogger{ClientIPHook: getClientIPFromEnv()}.Middleware
4✔
143
}
4✔
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