Files
AdGuardDNS/internal/cmd/cmd.go
Andrey Meshkov c1ba1c877a Sync v2.17.0
2025-11-07 13:47:40 +03:00

177 lines
4.2 KiB
Go

// Package cmd is the AdGuard DNS entry point. It contains the on-disk
// configuration file utilities, signal processing logic, and so on.
package cmd
import (
"context"
"os"
"os/signal"
"runtime"
"github.com/AdguardTeam/AdGuardDNS/internal/agd"
"github.com/AdguardTeam/AdGuardDNS/internal/cmd/plugin"
"github.com/AdguardTeam/AdGuardDNS/internal/experiment"
"github.com/AdguardTeam/AdGuardDNS/internal/metrics"
"github.com/AdguardTeam/AdGuardDNS/internal/version"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/sentryutil"
"golang.org/x/sys/unix"
)
// Main is the entry point of application.
func Main(plugins *plugin.Registry) {
// TODO(a.garipov, e.burkov): Consider adding timeouts for initialization.
ctx, stop := signal.NotifyContext(context.Background(), unix.SIGINT, unix.SIGTERM)
envs := errors.Must(parseEnvironment())
errors.Check(envs.Validate())
lvl := errors.Must(slogutil.VerbosityToLevel(envs.Verbosity))
baseLogger := slogutil.New(&slogutil.Config{
// Don't use [slogutil.NewFormat] here, because the value is validated.
Format: slogutil.Format(envs.LogFormat),
AddTimestamp: bool(envs.LogTimestamp),
Level: lvl,
})
sentryutil.SetDefaultLogger(baseLogger, "")
// TODO(a.garipov): Consider ways of replacing a prefix and stop passing
// the main logger everywhere.
mainLogger := baseLogger.With(slogutil.KeyPrefix, "main")
// Signal service startup now that we have the logs set up.
branch := version.Branch()
commitTime := version.CommitTime()
buildVersion := version.Version()
revision := version.Revision()
mainLogger.InfoContext(
ctx,
"agdns starting",
"version", buildVersion,
"revision", revision,
"branch", branch,
"commit_time", commitTime,
"race", version.RaceEnabled,
)
// Error collector
//
// TODO(a.garipov): Consider parsing SENTRY_DSN separately to set sentry up
// first and collect panics from the readEnvs call above as well.
errColl := errors.Must(envs.buildErrColl(baseLogger))
defer reportPanics(ctx, errColl, mainLogger)
setMaxThreads(ctx, mainLogger, envs.MaxThreads)
c := errors.Must(parseConfig(envs.ConfPath))
errors.Check(c.Validate())
profilesEnabled := c.isProfilesEnabled()
errors.Check(envs.validateProfilesConf(profilesEnabled))
// Building and running the server
b := newBuilder(&builderConfig{
envs: envs,
conf: c,
baseLogger: baseLogger,
plugins: plugins,
errColl: errColl,
profilesEnabled: profilesEnabled,
})
errors.Check(b.initCrashReporter(ctx))
errors.Check(experiment.Init(baseLogger, b.promRegisterer))
errors.Check(metrics.SetAdditionalInfo(b.promRegisterer, c.AdditionalMetricsInfo))
b.startGeoIP(ctx)
errors.Check(os.MkdirAll(envs.FilterCachePath, agd.DefaultDirPerm))
errors.Check(b.initMsgCloner(ctx))
errors.Check(b.initHashPrefixFilters(ctx))
errors.Check(b.initFilterStorage(ctx))
errors.Check(b.initFilteringGroups(ctx))
errors.Check(b.initAccess(ctx))
errors.Check(b.initBindToDevice(ctx))
errors.Check(b.initDNSDB(ctx))
errors.Check(b.initQueryLog(ctx))
errors.Check(b.initMsgConstructor(ctx))
errors.Check(b.initGRPCMetrics(ctx))
errors.Check(b.initStandardAccess(ctx))
errors.Check(b.initTLSManager(ctx))
errors.Check(b.initServerGroups(ctx))
errors.Check(b.initCustomDomainDB(ctx))
errors.Check(b.initTicketRotator(ctx))
errors.Check(b.startBindToDevice(ctx))
errors.Check(b.initBillStat(ctx))
errors.Check(b.initProfileDB(ctx))
errors.Check(b.refreshCustomDomainDB(ctx))
errors.Check(b.initDNSCheck(ctx))
errors.Check(b.initRuleStat(ctx))
errors.Check(b.initRateLimiter(ctx))
errors.Check(b.initWeb(ctx))
errors.Check(b.waitGeoIP(ctx))
errors.Check(b.initDNS(ctx))
errors.Check(b.performConnCheck(ctx))
errors.Check(b.initHealthCheck(ctx))
errors.Check(b.initPluginServices(ctx))
b.initPluginRefreshers()
b.mustStartDNS(ctx)
b.mustInitDebugSvc(ctx)
// Signal that the server is started.
errors.Check(metrics.SetUpGauge(
b.promRegisterer,
buildVersion,
branch,
commitTime,
revision,
runtime.Version(),
))
// Unregister the signal behavior for ctx.
stop()
ctx = context.WithoutCancel(ctx)
os.Exit(b.handleSignals(ctx))
}