Pull request 2624: AGDNS-3869-rm-the-old-logger-from-some-entities

Squashed commit of the following:

commit dc9d1f9448e0213e2484e9ad767c3015619a382a
Author: Maksim Kazantsev <m.kazantsev@adguard.com>
Date:   Fri Apr 10 12:39:28 2026 +0300

    home: upd var name;

commit ef34751d24f94e63376da13c0e0214011c29e213
Merge: 1a2cfce7e 397ed060d
Author: Ainar Garipov <a.garipov@adguard.com>
Date:   Fri Apr 10 12:26:58 2026 +0300

    Merge branch 'master' into AGDNS-3869-rm-the-old-logger-from-some-entities

commit 1a2cfce7ee595a058d7efced27964359174dcd50
Author: Maksim Kazantsev <m.kazantsev@adguard.com>
Date:   Thu Apr 9 16:47:50 2026 +0300

    home: imp docs; minor fix;

commit f5abd197848e768acef1c5f172e4b103719a7cf1
Author: Maksim Kazantsev <m.kazantsev@adguard.com>
Date:   Thu Apr 9 16:17:07 2026 +0300

    home: imp docs;

commit 6e1cf72512ae7a2dd4e31e6249bf1b1f08960d30
Author: Maksim Kazantsev <m.kazantsev@adguard.com>
Date:   Thu Apr 9 16:09:30 2026 +0300

    home: imp log;

commit 98c6fa0901428b241bbc5440bcd8b8ba06818cac
Author: Maksim Kazantsev <m.kazantsev@adguard.com>
Date:   Wed Apr 8 15:08:43 2026 +0300

    ossvc: actialize docs;

commit dad58759120e3fd1e042223523bf254dda925f21
Author: Maksim Kazantsev <m.kazantsev@adguard.com>
Date:   Wed Apr 8 14:52:27 2026 +0300

    home: imp code; add docs, contracts;

commit 334a75e58e514e0554a8a18963537ef03ce6b9de
Author: Maksim Kazantsev <m.kazantsev@adguard.com>
Date:   Wed Apr 8 13:36:04 2026 +0300

    home: rm old logger;
This commit is contained in:
Maksim Kazantsev committed 2026-04-10 09:48:40 +00:00
1 parent 397ed060d9
commit d28f33afca
7 files changed
+126 -64

No files matched your search

+26 -18
View File
@@ -18,7 +18,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghuser"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/netutil/httputil"
@@ -82,18 +81,27 @@ func realIP(r *http.Request) (ip netip.Addr, err error) {
}
// writeErrorWithIP is like [aghhttp.Error], but includes the remote IP address
// when it writes to the log.
func writeErrorWithIP(
// when it writes to the log. r, w and err must not be nil.
func (web *webAPI) writeErrorWithIP(
ctx context.Context,
err error,
r *http.Request,
w http.ResponseWriter,
code int,
remoteIP string,
format string,
args ...any,
) {
text := fmt.Sprintf(format, args...)
log.Error("%s %s %s: from ip %s: %s", r.Method, r.Host, r.URL, remoteIP, text)
http.Error(w, text, code)
web.logger.ErrorContext(
ctx,
"http error",
"host", r.Host,
"method", r.Method,
"url", r.URL,
"status", code,
"ip", remoteIP,
slogutil.KeyError, err,
)
http.Error(w, err.Error(), code)
}
// handleLogin is the handler for the POST /control/login HTTP API.
@@ -114,13 +122,13 @@ func (web *webAPI) handleLogin(w http.ResponseWriter, r *http.Request) {
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/2799.
if remoteIPStr, err = netutil.SplitHost(r.RemoteAddr); err != nil {
writeErrorWithIP(
web.writeErrorWithIP(
ctx,
fmt.Errorf("auth: getting remote address: %w", err),
r,
w,
http.StatusBadRequest,
r.RemoteAddr,
"auth: getting remote address: %s",
err,
)
return
@@ -129,13 +137,13 @@ func (web *webAPI) handleLogin(w http.ResponseWriter, r *http.Request) {
if rateLimiter := web.auth.rateLimiter; rateLimiter != nil {
if left := rateLimiter.check(remoteIPStr); left > 0 {
w.Header().Set(httphdr.RetryAfter, strconv.Itoa(int(left.Seconds())))
writeErrorWithIP(
web.writeErrorWithIP(
ctx,
fmt.Errorf("auth: blocked for %s", left),
r,
w,
http.StatusTooManyRequests,
remoteIPStr,
"auth: blocked for %s",
left,
)
return
@@ -154,13 +162,13 @@ func (web *webAPI) handleLogin(w http.ResponseWriter, r *http.Request) {
remoteIP, err := netip.ParseAddr(remoteIPStr)
if err != nil {
writeErrorWithIP(
web.writeErrorWithIP(
ctx,
fmt.Errorf("auth: parsing remote address: %w", err),
r,
w,
http.StatusInternalServerError,
r.RemoteAddr,
"auth: parsing remote address: %s",
err,
)
return
@@ -173,7 +181,7 @@ func (web *webAPI) handleLogin(w http.ResponseWriter, r *http.Request) {
cookie, err := newCookie(ctx, web.auth, req, remoteIPStr)
if err != nil {
writeErrorWithIP(r, w, http.StatusForbidden, logIP, "%s", err)
web.writeErrorWithIP(ctx, err, r, w, http.StatusForbidden, logIP)
return
}
+6 -2
View File
@@ -199,14 +199,18 @@ func (web *webAPI) registerControlHandlers() {
web.httpReg.Register(http.MethodGet, "/control/profile", web.handleGetProfile)
web.httpReg.Register(http.MethodPut, "/control/profile/update", web.handlePutProfile)
mobileConfHandler := newMobileConfigHandler(&mobileConfigHandlerConfig{
logger: web.baseLogger,
})
// No authentication is required for DoH/DoT configuration endpoints.
mux.Handle(
"/apple/doh.mobileconfig",
web.postInstallHandler(http.HandlerFunc(handleMobileConfigDoH)),
web.postInstallHandler(http.HandlerFunc(mobileConfHandler.handleMobileConfigDoH)),
)
mux.Handle(
"/apple/dot.mobileconfig",
web.postInstallHandler(http.HandlerFunc(handleMobileConfigDoT)),
web.postInstallHandler(http.HandlerFunc(mobileConfHandler.handleMobileConfigDoT)),
)
web.registerAuthHandlers()
+28 -22
View File
@@ -204,9 +204,9 @@ func setupContext(
// logIfUnsupported logs a formatted warning if the error is one of the
// unsupported errors and returns nil. If err is nil, logIfUnsupported returns
// nil. Otherwise, it returns err.
func logIfUnsupported(msg string, err error) (outErr error) {
func logIfUnsupported(ctx context.Context, l *slog.Logger, msg string, err error) (outErr error) {
if errors.Is(err, errors.ErrUnsupported) {
log.Debug(msg, err)
l.DebugContext(ctx, msg, slogutil.KeyError, err)
return nil
}
@@ -214,8 +214,9 @@ func logIfUnsupported(msg string, err error) (outErr error) {
return err
}
// configureOS sets the OS-related configuration.
func configureOS(conf *configuration) (err error) {
// configureOS sets the OS-related configuration. l and conf must not be nil.
// conf must be valid.
func configureOS(ctx context.Context, l *slog.Logger, conf *configuration) (err error) {
osConf := conf.OSConfig
if osConf == nil {
return nil
@@ -223,32 +224,32 @@ func configureOS(conf *configuration) (err error) {
if osConf.Group != "" {
err = aghos.SetGroup(osConf.Group)
err = logIfUnsupported("warning: setting group", err)
err = logIfUnsupported(ctx, l, "warning: setting group", err)
if err != nil {
return fmt.Errorf("setting group: %w", err)
}
log.Info("group set to %s", osConf.Group)
l.InfoContext(ctx, "group set", "groupname", osConf.Group)
}
if osConf.User != "" {
err = aghos.SetUser(osConf.User)
err = logIfUnsupported("warning: setting user", err)
err = logIfUnsupported(ctx, l, "warning: setting user", err)
if err != nil {
return fmt.Errorf("setting user: %w", err)
}
log.Info("user set to %s", osConf.User)
l.InfoContext(ctx, "user set", "username", osConf.User)
}
if osConf.RlimitNoFile != 0 {
err = aghos.SetRlimit(osConf.RlimitNoFile)
err = logIfUnsupported("warning: setting rlimit", err)
err = logIfUnsupported(ctx, l, "warning: setting rlimit", err)
if err != nil {
return fmt.Errorf("setting rlimit: %w", err)
}
log.Info("rlimit_nofile set to %d", osConf.RlimitNoFile)
l.InfoContext(ctx, "rlimit_nofile set", "rlimit_nofile", osConf.RlimitNoFile)
}
return nil
@@ -754,7 +755,7 @@ func run(
err := setupContext(ctx, baseLogger, opts, workDir, confPath, isFirstRun)
fatalOnError(err)
err = configureOS(config)
err = configureOS(ctx, baseLogger, config)
fatalOnError(err)
// Clients package uses filtering package's static data
@@ -1254,19 +1255,24 @@ func loadCmdLineOpts() (opts options) {
}
// printWebAddrs prints addresses built from proto, addr, and an appropriate
// port. At least one address is printed with the value of port. Output
// example:
// port. At least one address is printed with the value of port. l must not be
// nil. Output example:
//
// go to http://127.0.0.1:80
func printWebAddrs(proto, addr string, port uint16) {
log.Printf("go to %s://%s", proto, netutil.JoinHostPort(addr, port))
// 2026/04/08 14:01:43.794575 56031#1 [info] serving url=http://127.0.0.1:3000
func printWebAddrs(ctx context.Context, l *slog.Logger, proto, addr string, port uint16) {
u := &url.URL{
Scheme: proto,
Host: netutil.JoinHostPort(addr, port),
}
l.InfoContext(ctx, "serving", "url", u.String())
}
// printHTTPAddresses prints the IP addresses which user can use to access the
// admin interface. proto is either schemeHTTP or schemeHTTPS.
//
// TODO(s.chzhen): Implement separate functions for HTTP and HTTPS.
func printHTTPAddresses(proto string, tlsMgr *tlsManager) {
func printHTTPAddresses(ctx context.Context, l *slog.Logger, proto string, tlsMgr *tlsManager) {
var tlsConf *tlsConfigSettings
if tlsMgr != nil {
tlsConf = tlsMgr.config()
@@ -1278,32 +1284,32 @@ func printHTTPAddresses(proto string, tlsMgr *tlsManager) {
}
if proto == urlutil.SchemeHTTPS && tlsConf.ServerName != "" {
printWebAddrs(proto, tlsConf.ServerName, tlsConf.PortHTTPS)
printWebAddrs(ctx, l, proto, tlsConf.ServerName, tlsConf.PortHTTPS)
return
}
bindHost := config.HTTPConfig.Address.Addr()
if !bindHost.IsUnspecified() {
printWebAddrs(proto, bindHost.String(), port)
printWebAddrs(ctx, l, proto, bindHost.String(), port)
return
}
ifaces, err := aghnet.GetValidNetInterfacesForWeb()
if err != nil {
log.Error("web: getting iface ips: %s", err)
l.ErrorContext(ctx, "web: getting iface ips", slogutil.KeyError, err)
// That's weird, but we'll ignore it.
//
// TODO(e.burkov): Find out when it happens.
printWebAddrs(proto, bindHost.String(), port)
printWebAddrs(ctx, l, proto, bindHost.String(), port)
return
}
for _, iface := range ifaces {
for _, addr := range iface.Addresses {
printWebAddrs(proto, addr.String(), port)
printWebAddrs(ctx, l, proto, addr.String(), port)
}
}
}
+47 -11
View File
@@ -1,8 +1,10 @@
package home
import (
"context"
"encoding/json"
"fmt"
"log/slog"
"net"
"net/http"
"net/url"
@@ -12,7 +14,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/httphdr"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil/urlutil"
"github.com/google/uuid"
"howett.net/plist"
@@ -90,6 +92,27 @@ const (
dnsProtoTLS = "TLS"
)
// mobileConfigHandlerConfig is the configuration structure for
// [newMobileConfigHandler].
type mobileConfigHandlerConfig struct {
// logger is used for logging the operations of mobile config handler. It
// must not be nil.
logger *slog.Logger
}
// mobileConfigHandler handles mobile-config related operations.
type mobileConfigHandler struct {
logger *slog.Logger
}
// newMobileConfigHandler creates a new instance of [*mobileConfigHandler]. c
// must not be nil and must be valid.
func newMobileConfigHandler(c *mobileConfigHandlerConfig) *mobileConfigHandler {
return &mobileConfigHandler{
logger: c.logger.With(slogutil.KeyPrefix, "mobile_handler"),
}
}
func encodeMobileConfig(d *dnsSettings, clientID string) ([]byte, error) {
var dspName string
switch proto := d.DNSProtocol; proto {
@@ -142,25 +165,36 @@ func encodeMobileConfig(d *dnsSettings, clientID string) ([]byte, error) {
return plist.MarshalIndent(data, plist.XMLFormat, "\t")
}
func respondJSONError(w http.ResponseWriter, status int, msg string) {
// respondJSONError writes an internal server error to the header and responds
// to the client with an error. l and w must not be nil.
func respondJSONError(
ctx context.Context,
l *slog.Logger,
w http.ResponseWriter,
status int,
msg string,
) {
w.WriteHeader(http.StatusInternalServerError)
err := json.NewEncoder(w).Encode(&jsonError{
Message: msg,
})
if err != nil {
log.Debug("writing %d json response: %s", status, err)
l.DebugContext(ctx, "writing json response", "status", status, slogutil.KeyError, err)
}
}
// errEmptyHost error indicates that the host and server names are missing from
// the query parameters.
const errEmptyHost errors.Error = "no host in query parameters and no server_name"
func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) {
func (m *mobileConfigHandler) handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) {
var err error
ctx := r.Context()
q := r.URL.Query()
host := q.Get("host")
if host == "" {
respondJSONError(w, http.StatusInternalServerError, string(errEmptyHost))
respondJSONError(ctx, m.logger, w, http.StatusInternalServerError, string(errEmptyHost))
return
}
@@ -169,7 +203,7 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) {
if clientID != "" {
err = client.ValidateClientID(clientID)
if err != nil {
respondJSONError(w, http.StatusBadRequest, err.Error())
respondJSONError(ctx, m.logger, w, http.StatusBadRequest, err.Error())
return
}
@@ -182,7 +216,7 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) {
mobileconfig, err := encodeMobileConfig(d, clientID)
if err != nil {
respondJSONError(w, http.StatusInternalServerError, err.Error())
respondJSONError(ctx, m.logger, w, http.StatusInternalServerError, err.Error())
return
}
@@ -204,10 +238,12 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) {
_, _ = w.Write(mobileconfig)
}
func handleMobileConfigDoH(w http.ResponseWriter, r *http.Request) {
handleMobileConfig(w, r, dnsProtoHTTPS)
// handleMobileConfigDoH handles getting DNS-over-HTTPS .mobileconfig.
func (m *mobileConfigHandler) handleMobileConfigDoH(w http.ResponseWriter, r *http.Request) {
m.handleMobileConfig(w, r, dnsProtoHTTPS)
}
func handleMobileConfigDoT(w http.ResponseWriter, r *http.Request) {
handleMobileConfig(w, r, dnsProtoTLS)
// handleMobileConfigDoT handles getting DNS-over-TLS .mobileconfig.
func (m *mobileConfigHandler) handleMobileConfigDoT(w http.ResponseWriter, r *http.Request) {
m.handleMobileConfig(w, r, dnsProtoTLS)
}
+16 -8
View File
@@ -31,16 +31,20 @@ func setupDNSIPs(tb testing.TB) {
}
}
func TestHandleMobileConfigDoH(t *testing.T) {
func TestMobileConfigHandler_HandleMobileConfigDoH(t *testing.T) {
setupDNSIPs(t)
mobileConfHandler := newMobileConfigHandler(&mobileConfigHandlerConfig{
logger: testLogger,
})
t.Run("success", func(t *testing.T) {
r, err := http.NewRequest(http.MethodGet, "https://example.com:12345/apple/doh.mobileconfig?host=example.org", nil)
require.NoError(t, err)
w := httptest.NewRecorder()
handleMobileConfigDoH(w, r)
mobileConfHandler.handleMobileConfigDoH(w, r)
require.Equal(t, http.StatusOK, w.Code)
var mc mobileConfig
@@ -69,7 +73,7 @@ func TestHandleMobileConfigDoH(t *testing.T) {
w := httptest.NewRecorder()
handleMobileConfigDoH(w, r)
mobileConfHandler.handleMobileConfigDoH(w, r)
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.JSONEq(t, w.Body.String(), b.String())
})
@@ -80,7 +84,7 @@ func TestHandleMobileConfigDoH(t *testing.T) {
w := httptest.NewRecorder()
handleMobileConfigDoH(w, r)
mobileConfHandler.handleMobileConfigDoH(w, r)
require.Equal(t, http.StatusOK, w.Code)
var mc mobileConfig
@@ -98,16 +102,20 @@ func TestHandleMobileConfigDoH(t *testing.T) {
})
}
func TestHandleMobileConfigDoT(t *testing.T) {
func TestMobileConfigHandler_HandleMobileConfigDoT(t *testing.T) {
setupDNSIPs(t)
mobileConfHandler := newMobileConfigHandler(&mobileConfigHandlerConfig{
logger: testLogger,
})
t.Run("success", func(t *testing.T) {
r, err := http.NewRequest(http.MethodGet, "https://example.com:12345/apple/dot.mobileconfig?host=example.org", nil)
require.NoError(t, err)
w := httptest.NewRecorder()
handleMobileConfigDoT(w, r)
mobileConfHandler.handleMobileConfigDoT(w, r)
require.Equal(t, http.StatusOK, w.Code)
var mc mobileConfig
@@ -136,7 +144,7 @@ func TestHandleMobileConfigDoT(t *testing.T) {
w := httptest.NewRecorder()
handleMobileConfigDoT(w, r)
mobileConfHandler.handleMobileConfigDoT(w, r)
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.JSONEq(t, w.Body.String(), b.String())
})
@@ -147,7 +155,7 @@ func TestHandleMobileConfigDoT(t *testing.T) {
w := httptest.NewRecorder()
handleMobileConfigDoT(w, r)
mobileConfHandler.handleMobileConfigDoT(w, r)
require.Equal(t, http.StatusOK, w.Code)
var mc mobileConfig
+1 -1
View File
@@ -320,7 +320,7 @@ func handleServiceInstallCmd(
"There are a few more things that must be configured before you can use it.\n"+
"Click on the link below and follow the Installation Wizard steps to finish setup.\n"+
"AdGuard Home is now available at the following addresses:")
printHTTPAddresses(urlutil.SchemeHTTP, nil)
printHTTPAddresses(ctx, l, urlutil.SchemeHTTP, nil)
}
return nil
+2 -2
View File
@@ -262,7 +262,7 @@ func (web *webAPI) start(ctx context.Context) {
// this loop is used as an ability to change listening host and/or port
for !web.httpsServer.inShutdown {
printHTTPAddresses(urlutil.SchemeHTTP, web.tlsManager)
printHTTPAddresses(ctx, web.logger, urlutil.SchemeHTTP, web.tlsManager)
errs := make(chan error, 2)
hdlr := withMiddlewares(web.conf.mux, limitRequestBody)
@@ -381,7 +381,7 @@ func (web *webAPI) serveTLS(ctx context.Context) (next bool) {
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
}
printHTTPAddresses(urlutil.SchemeHTTPS, web.tlsManager)
printHTTPAddresses(ctx, web.logger, urlutil.SchemeHTTPS, web.tlsManager)
if web.conf.serveHTTP3 {
go web.mustStartHTTP3(ctx, addr)