diff --git a/internal/cache/default.go b/internal/cache/default.go
index 4558fb26..399cc84c 100644
--- a/internal/cache/default.go
+++ b/internal/cache/default.go
@@ -5,7 +5,6 @@
 package cache
 
 import (
-	"errors"
 	"fmt"
 	"log"
 	"os"
@@ -13,6 +12,8 @@ import (
 	"sync"
 )
 
+const envGolangciLintCache = "GOLANGCI_LINT_CACHE"
+
 // Default returns the default cache to use.
 func Default() (*Cache, error) {
 	defaultOnce.Do(initDefaultCache)
@@ -65,19 +66,19 @@ func DefaultDir() string {
 	// otherwise distinguish between an explicit "off" and a UserCacheDir error.
 
 	defaultDirOnce.Do(func() {
-		defaultDir = os.Getenv("GOLANGCI_LINT_CACHE")
+		defaultDir = os.Getenv(envGolangciLintCache)
 		if filepath.IsAbs(defaultDir) {
 			return
 		}
 		if defaultDir != "" {
-			defaultDirErr = errors.New("GOLANGCI_LINT_CACHE is not an absolute path")
+			defaultDirErr = fmt.Errorf("%s is not an absolute path", envGolangciLintCache)
 			return
 		}
 
 		// Compute default location.
 		dir, err := os.UserCacheDir()
 		if err != nil {
-			defaultDirErr = fmt.Errorf("GOLANGCI_LINT_CACHE is not defined and %v", err)
+			defaultDirErr = fmt.Errorf("%s is not defined and %w", envGolangciLintCache, err)
 			return
 		}
 		defaultDir = filepath.Join(dir, "golangci-lint")
diff --git a/pkg/commands/executor.go b/pkg/commands/executor.go
index 2723f5c0..6dc3b74b 100644
--- a/pkg/commands/executor.go
+++ b/pkg/commands/executor.go
@@ -64,11 +64,11 @@ func NewExecutor(version, commit, date string) *Executor {
 		commit:    commit,
 		date:      date,
 		DBManager: lintersdb.NewManager(nil, nil),
-		debugf:    logutils.Debug("exec"),
+		debugf:    logutils.Debug(logutils.DebugKeyExec),
 	}
 
 	e.debugf("Starting execution...")
-	e.log = report.NewLogWrapper(logutils.NewStderrLog(""), &e.reportData)
+	e.log = report.NewLogWrapper(logutils.NewStderrLog(logutils.DebugKeyEmpty), &e.reportData)
 
 	// to setup log level early we need to parse config from command line extra time to
 	// find `-v` option
@@ -105,7 +105,7 @@ func NewExecutor(version, commit, date string) *Executor {
 	// like the default ones. It will overwrite them only if the same option
 	// is found in command-line: it's ok, command-line has higher priority.
 
-	r := config.NewFileReader(e.cfg, commandLineCfg, e.log.Child("config_reader"))
+	r := config.NewFileReader(e.cfg, commandLineCfg, e.log.Child(logutils.DebugKeyConfigReader))
 	if err = r.Read(); err != nil {
 		e.log.Fatalf("Can't read config: %s", err)
 	}
@@ -122,18 +122,18 @@ func NewExecutor(version, commit, date string) *Executor {
 	fixSlicesFlags(e.lintersCmd.Flags())
 
 	e.EnabledLintersSet = lintersdb.NewEnabledSet(e.DBManager,
-		lintersdb.NewValidator(e.DBManager), e.log.Child("lintersdb"), e.cfg)
-	e.goenv = goutil.NewEnv(e.log.Child("goenv"))
+		lintersdb.NewValidator(e.DBManager), e.log.Child(logutils.DebugKeyLintersDB), e.cfg)
+	e.goenv = goutil.NewEnv(e.log.Child(logutils.DebugKeyGoEnv))
 	e.fileCache = fsutils.NewFileCache()
 	e.lineCache = fsutils.NewLineCache(e.fileCache)
 
-	e.sw = timeutils.NewStopwatch("pkgcache", e.log.Child("stopwatch"))
-	e.pkgCache, err = pkgcache.NewCache(e.sw, e.log.Child("pkgcache"))
+	e.sw = timeutils.NewStopwatch("pkgcache", e.log.Child(logutils.DebugKeyStopwatch))
+	e.pkgCache, err = pkgcache.NewCache(e.sw, e.log.Child(logutils.DebugKeyPkgCache))
 	if err != nil {
 		e.log.Fatalf("Failed to build packages cache: %s", err)
 	}
 	e.loadGuard = load.NewGuard()
-	e.contextLoader = lint.NewContextLoader(e.cfg, e.log.Child("loader"), e.goenv,
+	e.contextLoader = lint.NewContextLoader(e.cfg, e.log.Child(logutils.DebugKeyLoader), e.goenv,
 		e.lineCache, e.fileCache, e.pkgCache, e.loadGuard)
 	if err = e.initHashSalt(version); err != nil {
 		e.log.Fatalf("Failed to init hash salt: %s", err)
@@ -169,7 +169,7 @@ func computeBinarySalt(version string) ([]byte, error) {
 		return []byte(version), nil
 	}
 
-	if logutils.HaveDebugTag("bin_salt") {
+	if logutils.HaveDebugTag(logutils.DebugKeyBinSalt) {
 		return []byte("debug"), nil
 	}
 
diff --git a/pkg/commands/root.go b/pkg/commands/root.go
index c29e6560..0fdcccff 100644
--- a/pkg/commands/root.go
+++ b/pkg/commands/root.go
@@ -16,6 +16,12 @@ import (
 	"github.com/golangci/golangci-lint/pkg/logutils"
 )
 
+const (
+	// envHelpRun value: "1".
+	envHelpRun        = "HELP_RUN"
+	envMemProfileRate = "GL_MEM_PROFILE_RATE"
+)
+
 func (e *Executor) persistentPreRun(_ *cobra.Command, _ []string) error {
 	if e.cfg.Run.PrintVersion {
 		_, _ = fmt.Fprintf(logutils.StdOut, "golangci-lint has version %s built from %s on %s\n", e.version, e.commit, e.date)
@@ -35,7 +41,7 @@ func (e *Executor) persistentPreRun(_ *cobra.Command, _ []string) error {
 	}
 
 	if e.cfg.Run.MemProfilePath != "" {
-		if rate := os.Getenv("GL_MEMPROFILE_RATE"); rate != "" {
+		if rate := os.Getenv(envMemProfileRate); rate != "" {
 			runtime.MemProfileRate, _ = strconv.Atoi(rate)
 		}
 	}
@@ -112,7 +118,7 @@ func formatMemory(memBytes uint64) string {
 }
 
 func getDefaultConcurrency() int {
-	if os.Getenv("HELP_RUN") == "1" {
+	if os.Getenv(envHelpRun) == "1" {
 		// Make stable concurrency for README help generating builds.
 		const prettyConcurrency = 8
 		return prettyConcurrency
diff --git a/pkg/commands/run.go b/pkg/commands/run.go
index 9f9d5ea4..8106dbdb 100644
--- a/pkg/commands/run.go
+++ b/pkg/commands/run.go
@@ -28,6 +28,13 @@ import (
 
 const defaultFileMode = 0644
 
+const (
+	// envFailOnWarnings value: "1"
+	envFailOnWarnings = "FAIL_ON_WARNINGS"
+	// envMemLogEvery value: "1"
+	envMemLogEvery = "GL_MEM_LOG_EVERY"
+)
+
 func getDefaultIssueExcludeHelp() string {
 	parts := []string{"Use or not use default excludes:"}
 	for _, ep := range config.DefaultExcludePatterns {
@@ -350,9 +357,9 @@ func (e *Executor) runAnalysis(ctx context.Context, args []string) ([]result.Iss
 	if err != nil {
 		return nil, errors.Wrap(err, "context loading failed")
 	}
-	lintCtx.Log = e.log.Child("linters context")
+	lintCtx.Log = e.log.Child(logutils.DebugKeyLintersContext)
 
-	runner, err := lint.NewRunner(e.cfg, e.log.Child("runner"),
+	runner, err := lint.NewRunner(e.cfg, e.log.Child(logutils.DebugKeyRunner),
 		e.goenv, e.EnabledLintersSet, e.lineCache, e.DBManager, lintCtx.Packages)
 	if err != nil {
 		return nil, err
@@ -390,7 +397,7 @@ func (e *Executor) runAndPrint(ctx context.Context, args []string) error {
 		e.log.Warnf("Failed to discover go env: %s", err)
 	}
 
-	if !logutils.HaveDebugTag("linters_output") {
+	if !logutils.HaveDebugTag(logutils.DebugKeyLintersOutput) {
 		// Don't allow linters and loader to print anything
 		log.SetOutput(io.Discard)
 		savedStdout, savedStderr := e.setOutputToDevNull()
@@ -474,9 +481,9 @@ func (e *Executor) createPrinter(format string, w io.Writer) (printers.Printer,
 	case config.OutFormatColoredLineNumber, config.OutFormatLineNumber:
 		p = printers.NewText(e.cfg.Output.PrintIssuedLine,
 			format == config.OutFormatColoredLineNumber, e.cfg.Output.PrintLinterName,
-			e.log.Child("text_printer"), w)
+			e.log.Child(logutils.DebugKeyTextPrinter), w)
 	case config.OutFormatTab:
-		p = printers.NewTab(e.cfg.Output.PrintLinterName, e.log.Child("tab_printer"), w)
+		p = printers.NewTab(e.cfg.Output.PrintLinterName, e.log.Child(logutils.DebugKeyTabPrinter), w)
 	case config.OutFormatCheckstyle:
 		p = printers.NewCheckstyle(w)
 	case config.OutFormatCodeClimate:
@@ -545,7 +552,7 @@ func (e *Executor) setupExitCode(ctx context.Context) {
 		return
 	}
 
-	needFailOnWarnings := os.Getenv("GL_TEST_RUN") == "1" || os.Getenv("FAIL_ON_WARNINGS") == "1"
+	needFailOnWarnings := os.Getenv(lintersdb.EnvTestRun) == "1" || os.Getenv(envFailOnWarnings) == "1"
 	if needFailOnWarnings && len(e.reportData.Warnings) != 0 {
 		e.exitCode = exitcodes.WarningInTest
 		return
@@ -569,7 +576,7 @@ func watchResources(ctx context.Context, done chan struct{}, logger logutils.Log
 	ticker := time.NewTicker(intervalMS * time.Millisecond)
 	defer ticker.Stop()
 
-	logEveryRecord := os.Getenv("GL_MEM_LOG_EVERY") == "1"
+	logEveryRecord := os.Getenv(envMemLogEvery) == "1"
 	const MB = 1024 * 1024
 
 	track := func() {
diff --git a/pkg/golinters/commons.go b/pkg/golinters/commons.go
index a4c3913f..3b40e59b 100644
--- a/pkg/golinters/commons.go
+++ b/pkg/golinters/commons.go
@@ -3,4 +3,4 @@ package golinters
 import "github.com/golangci/golangci-lint/pkg/logutils"
 
 // linterLogger must be use only when the context logger is not available.
-var linterLogger = logutils.NewStderrLog("linter")
+var linterLogger = logutils.NewStderrLog(logutils.DebugKeyLinter)
diff --git a/pkg/golinters/goanalysis/runner.go b/pkg/golinters/goanalysis/runner.go
index c52998fb..4a52c110 100644
--- a/pkg/golinters/goanalysis/runner.go
+++ b/pkg/golinters/goanalysis/runner.go
@@ -28,17 +28,17 @@ import (
 )
 
 var (
-	debugf = logutils.Debug("goanalysis")
+	debugf = logutils.Debug(logutils.DebugKeyGoAnalysis)
 
-	analyzeDebugf     = logutils.Debug("goanalysis/analyze")
-	isMemoryDebug     = logutils.HaveDebugTag("goanalysis/memory")
-	issuesCacheDebugf = logutils.Debug("goanalysis/issues/cache")
+	analyzeDebugf     = logutils.Debug(logutils.DebugKeyGoAnalysisAnalyze)
+	isMemoryDebug     = logutils.HaveDebugTag(logutils.DebugKeyGoAnalysisMemory)
+	issuesCacheDebugf = logutils.Debug(logutils.DebugKeyGoAnalysisIssuesCache)
 
-	factsDebugf        = logutils.Debug("goanalysis/facts")
-	factsCacheDebugf   = logutils.Debug("goanalysis/facts/cache")
-	factsInheritDebugf = logutils.Debug("goanalysis/facts/inherit")
-	factsExportDebugf  = logutils.Debug("goanalysis/facts")
-	isFactsExportDebug = logutils.HaveDebugTag("goanalysis/facts/export")
+	factsDebugf        = logutils.Debug(logutils.DebugKeyGoAnalysisFacts)
+	factsCacheDebugf   = logutils.Debug(logutils.DebugKeyGoAnalysisFactsCache)
+	factsInheritDebugf = logutils.Debug(logutils.DebugKeyGoAnalysisFactsInherit)
+	factsExportDebugf  = logutils.Debug(logutils.DebugKeyGoAnalysisFacts)
+	isFactsExportDebug = logutils.HaveDebugTag(logutils.DebugKeyGoAnalysisFactsExport)
 )
 
 type Diagnostic struct {
diff --git a/pkg/golinters/goanalysis/runners.go b/pkg/golinters/goanalysis/runners.go
index 7e4cf902..559fb139 100644
--- a/pkg/golinters/goanalysis/runners.go
+++ b/pkg/golinters/goanalysis/runners.go
@@ -14,6 +14,7 @@ import (
 
 	"github.com/golangci/golangci-lint/internal/pkgcache"
 	"github.com/golangci/golangci-lint/pkg/lint/linter"
+	"github.com/golangci/golangci-lint/pkg/logutils"
 	"github.com/golangci/golangci-lint/pkg/result"
 	"github.com/golangci/golangci-lint/pkg/timeutils"
 )
@@ -28,7 +29,7 @@ type runAnalyzersConfig interface {
 }
 
 func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]result.Issue, error) {
-	log := lintCtx.Log.Child("goanalysis")
+	log := lintCtx.Log.Child(logutils.DebugKeyGoAnalysis)
 	sw := timeutils.NewStopwatch("analyzers", log)
 
 	const stagesToPrint = 10
diff --git a/pkg/golinters/gocritic.go b/pkg/golinters/gocritic.go
index 7b509e8d..0b4af06a 100644
--- a/pkg/golinters/gocritic.go
+++ b/pkg/golinters/gocritic.go
@@ -26,8 +26,8 @@ import (
 const goCriticName = "gocritic"
 
 var (
-	goCriticDebugf  = logutils.Debug(goCriticName)
-	isGoCriticDebug = logutils.HaveDebugTag(goCriticName)
+	goCriticDebugf  = logutils.Debug(logutils.DebugKeyGoCritic)
+	isGoCriticDebug = logutils.HaveDebugTag(logutils.DebugKeyGoCritic)
 )
 
 func NewGoCritic(settings *config.GoCriticSettings, cfg *config.Config) *goanalysis.Linter {
diff --git a/pkg/golinters/revive.go b/pkg/golinters/revive.go
index 5c160665..faa9e024 100644
--- a/pkg/golinters/revive.go
+++ b/pkg/golinters/revive.go
@@ -25,7 +25,7 @@ import (
 
 const reviveName = "revive"
 
-var reviveDebugf = logutils.Debug("revive")
+var reviveDebugf = logutils.Debug(logutils.DebugKeyRevive)
 
 // jsonObject defines a JSON object of a failure
 type jsonObject struct {
diff --git a/pkg/golinters/staticcheck_common.go b/pkg/golinters/staticcheck_common.go
index b421d30c..0eb21ec9 100644
--- a/pkg/golinters/staticcheck_common.go
+++ b/pkg/golinters/staticcheck_common.go
@@ -12,7 +12,7 @@ import (
 	"github.com/golangci/golangci-lint/pkg/logutils"
 )
 
-var debugf = logutils.Debug("megacheck")
+var debugf = logutils.Debug(logutils.DebugKeyMegacheck)
 
 func getGoVersion(settings *config.StaticCheckSettings) string {
 	var goVersion string
diff --git a/pkg/goutil/env.go b/pkg/goutil/env.go
index 1c05b980..4873f3f9 100644
--- a/pkg/goutil/env.go
+++ b/pkg/goutil/env.go
@@ -30,7 +30,7 @@ func NewEnv(log logutils.Log) *Env {
 	return &Env{
 		vars:   map[string]string{},
 		log:    log,
-		debugf: logutils.Debug("env"),
+		debugf: logutils.Debug(logutils.DebugKeyEnv),
 	}
 }
 
diff --git a/pkg/lint/lintersdb/enabled_set.go b/pkg/lint/lintersdb/enabled_set.go
index 907c1c4d..92615b57 100644
--- a/pkg/lint/lintersdb/enabled_set.go
+++ b/pkg/lint/lintersdb/enabled_set.go
@@ -10,6 +10,9 @@ import (
 	"github.com/golangci/golangci-lint/pkg/logutils"
 )
 
+// EnvTestRun value: "1"
+const EnvTestRun = "GL_TEST_RUN"
+
 type EnabledSet struct {
 	m      *Manager
 	v      *Validator
@@ -24,7 +27,7 @@ func NewEnabledSet(m *Manager, v *Validator, log logutils.Log, cfg *config.Confi
 		v:      v,
 		log:    log,
 		cfg:    cfg,
-		debugf: logutils.Debug("enabled_linters"),
+		debugf: logutils.Debug(logutils.DebugKeyEnabledLinters),
 	}
 }
 
@@ -84,7 +87,7 @@ func (es EnabledSet) GetEnabledLintersMap() (map[string]*linter.Config, error) {
 	}
 
 	enabledLinters := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters())
-	if os.Getenv("GL_TEST_RUN") == "1" {
+	if os.Getenv(EnvTestRun) == "1" {
 		es.verbosePrintLintersStatus(enabledLinters)
 	}
 	return enabledLinters, nil
diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go
index b17ce3be..bdbd5e49 100644
--- a/pkg/lint/lintersdb/manager.go
+++ b/pkg/lint/lintersdb/manager.go
@@ -38,7 +38,7 @@ func NewManager(cfg *config.Config, log logutils.Log) *Manager {
 // WithCustomLinters loads private linters that are specified in the golangci config file.
 func (m *Manager) WithCustomLinters() *Manager {
 	if m.log == nil {
-		m.log = report.NewLogWrapper(logutils.NewStderrLog(""), &report.Data{})
+		m.log = report.NewLogWrapper(logutils.NewStderrLog(logutils.DebugKeyEmpty), &report.Data{})
 	}
 	if m.cfg != nil {
 		for name, settings := range m.cfg.LintersSettings.Custom {
diff --git a/pkg/lint/load.go b/pkg/lint/load.go
index 8935134e..0bac1062 100644
--- a/pkg/lint/load.go
+++ b/pkg/lint/load.go
@@ -41,7 +41,7 @@ func NewContextLoader(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
 	return &ContextLoader{
 		cfg:         cfg,
 		log:         log,
-		debugf:      logutils.Debug("loader"),
+		debugf:      logutils.Debug(logutils.DebugKeyLoader),
 		goenv:       goenv,
 		pkgTestIDRe: regexp.MustCompile(`^(.*) \[(.*)\.test\]`),
 		lineCache:   lineCache,
@@ -59,7 +59,7 @@ func (cl *ContextLoader) prepareBuildContext() {
 		return
 	}
 
-	os.Setenv("GOROOT", goroot)
+	os.Setenv(string(goutil.EnvGoRoot), goroot)
 	build.Default.GOROOT = goroot
 	build.Default.BuildTags = cl.cfg.Run.BuildTags
 }
diff --git a/pkg/lint/runner.go b/pkg/lint/runner.go
index e1a77c7d..b21635f0 100644
--- a/pkg/lint/runner.go
+++ b/pkg/lint/runner.go
@@ -39,7 +39,7 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint
 	if cfg.Run.UseDefaultSkipDirs {
 		skipDirs = append(skipDirs, packages.StdExcludeDirRegexps...)
 	}
-	skipDirsProcessor, err := processors.NewSkipDirs(skipDirs, log.Child("skip dirs"), cfg.Run.Args)
+	skipDirsProcessor, err := processors.NewSkipDirs(skipDirs, log.Child(logutils.DebugKeySkipDirs), cfg.Run.Args)
 	if err != nil {
 		return nil, err
 	}
@@ -70,7 +70,7 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint
 			processors.NewCgo(goenv),
 
 			// Must go after Cgo.
-			processors.NewFilenameUnadjuster(pkgs, log.Child("filename_unadjuster")),
+			processors.NewFilenameUnadjuster(pkgs, log.Child(logutils.DebugKeyFilenameUnadjuster)),
 
 			// Must be before diff, nolint and exclude autogenerated processor at least.
 			processors.NewPathPrettifier(),
@@ -84,14 +84,14 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint
 
 			getExcludeProcessor(&cfg.Issues),
 			getExcludeRulesProcessor(&cfg.Issues, log, lineCache),
-			processors.NewNolint(log.Child("nolint"), dbManager, enabledLinters),
+			processors.NewNolint(log.Child(logutils.DebugKeyNolint), dbManager, enabledLinters),
 
 			processors.NewUniqByLine(cfg),
 			processors.NewDiff(cfg.Issues.Diff, cfg.Issues.DiffFromRevision, cfg.Issues.DiffPatchFilePath, cfg.Issues.WholeFiles),
 			processors.NewMaxPerFileFromLinter(cfg),
-			processors.NewMaxSameIssues(cfg.Issues.MaxSameIssues, log.Child("max_same_issues"), cfg),
-			processors.NewMaxFromLinter(cfg.Issues.MaxIssuesPerLinter, log.Child("max_from_linter"), cfg),
-			processors.NewSourceCode(lineCache, log.Child("source_code")),
+			processors.NewMaxSameIssues(cfg.Issues.MaxSameIssues, log.Child(logutils.DebugKeyMaxSameIssues), cfg),
+			processors.NewMaxFromLinter(cfg.Issues.MaxIssuesPerLinter, log.Child(logutils.DebugKeyMaxFromLinter), cfg),
+			processors.NewSourceCode(lineCache, log.Child(logutils.DebugKeySourceCode)),
 			processors.NewPathShortener(),
 			getSeverityRulesProcessor(&cfg.Severity, log, lineCache),
 			processors.NewPathPrefixer(cfg.Output.PathPrefix),
@@ -288,13 +288,13 @@ func getExcludeRulesProcessor(cfg *config.Issues, log logutils.Log, lineCache *f
 		excludeRulesProcessor = processors.NewExcludeRulesCaseSensitive(
 			excludeRules,
 			lineCache,
-			log.Child("exclude_rules"),
+			log.Child(logutils.DebugKeyExcludeRules),
 		)
 	} else {
 		excludeRulesProcessor = processors.NewExcludeRules(
 			excludeRules,
 			lineCache,
-			log.Child("exclude_rules"),
+			log.Child(logutils.DebugKeyExcludeRules),
 		)
 	}
 
@@ -321,14 +321,14 @@ func getSeverityRulesProcessor(cfg *config.Severity, log logutils.Log, lineCache
 			cfg.Default,
 			severityRules,
 			lineCache,
-			log.Child("severity_rules"),
+			log.Child(logutils.DebugKeySeverityRules),
 		)
 	} else {
 		severityRulesProcessor = processors.NewSeverityRules(
 			cfg.Default,
 			severityRules,
 			lineCache,
-			log.Child("severity_rules"),
+			log.Child(logutils.DebugKeySeverityRules),
 		)
 	}
 
diff --git a/pkg/logutils/log.go b/pkg/logutils/log.go
index 57c35c78..2c9609d8 100644
--- a/pkg/logutils/log.go
+++ b/pkg/logutils/log.go
@@ -14,18 +14,18 @@ type Log interface {
 type LogLevel int
 
 const (
-	// Debug messages, write to debug logs only by logutils.Debug.
+	// LogLevelDebug Debug messages, write to debug logs only by logutils.Debug.
 	LogLevelDebug LogLevel = 0
 
-	// Information messages, don't write too many messages,
+	// LogLevelInfo Information messages, don't write too many messages,
 	// only useful ones: they are shown when running with -v.
 	LogLevelInfo LogLevel = 1
 
-	// Hidden errors: non-critical errors: work can be continued, no need to fail whole program;
+	// LogLevelWarn Hidden errors: non-critical errors: work can be continued, no need to fail whole program;
 	// tests will crash if any warning occurred.
 	LogLevelWarn LogLevel = 2
 
-	// Only not hidden from user errors: whole program failing, usually
+	// LogLevelError Only not hidden from user errors: whole program failing, usually
 	// error logging happens in 1-2 places: in the "main" function.
 	LogLevelError LogLevel = 3
 )
diff --git a/pkg/logutils/logutils.go b/pkg/logutils/logutils.go
index 93c9873d..710f084a 100644
--- a/pkg/logutils/logutils.go
+++ b/pkg/logutils/logutils.go
@@ -5,9 +5,65 @@ import (
 	"strings"
 )
 
+// envDebug value: one or several debug keys.
+// examples:
+// - Remove output to `/dev/null`: `GL_DEBUG=linters_output ./golangci-lint run`
+// - Show linters configuration: `GL_DEBUG=enabled_linters golangci-lint run`
+// - Some analysis details: `GL_DEBUG=goanalysis/analyze,goanalysis/facts golangci-lint run`
+const envDebug = "GL_DEBUG"
+
+const (
+	DebugKeyAutogenExclude     = "autogen_exclude"
+	DebugKeyBinSalt            = "bin_salt"
+	DebugKeyConfigReader       = "config_reader"
+	DebugKeyEmpty              = ""
+	DebugKeyEnabledLinters     = "enabled_linters"
+	DebugKeyEnv                = "env"
+	DebugKeyExcludeRules       = "exclude_rules"
+	DebugKeyExec               = "exec"
+	DebugKeyFilenameUnadjuster = "filename_unadjuster"
+	DebugKeyGoEnv              = "goenv"
+	DebugKeyLinter             = "linter"
+	DebugKeyLintersContext     = "linters_context"
+	DebugKeyLintersDB          = "lintersdb"
+	DebugKeyLintersOutput      = "linters_output"
+	DebugKeyLoader             = "loader"
+	DebugKeyMaxFromLinter      = "max_from_linter"
+	DebugKeyMaxSameIssues      = "max_same_issues"
+	DebugKeyPkgCache           = "pkgcache"
+	DebugKeyRunner             = "runner"
+	DebugKeySeverityRules      = "severity_rules"
+	DebugKeySkipDirs           = "skip_dirs"
+	DebugKeySourceCode         = "source_code"
+	DebugKeyStopwatch          = "stopwatch"
+	DebugKeyTabPrinter         = "tab_printer"
+	DebugKeyTest               = "test"
+	DebugKeyTextPrinter        = "text_printer"
+)
+
+const (
+	DebugKeyGoAnalysis = "goanalysis"
+
+	DebugKeyGoAnalysisAnalyze     = DebugKeyGoAnalysis + "/analyze"
+	DebugKeyGoAnalysisIssuesCache = DebugKeyGoAnalysis + "/issues/cache"
+	DebugKeyGoAnalysisMemory      = DebugKeyGoAnalysis + "/memory"
+
+	DebugKeyGoAnalysisFacts        = DebugKeyGoAnalysis + "/facts"
+	DebugKeyGoAnalysisFactsCache   = DebugKeyGoAnalysisFacts + "/cache"
+	DebugKeyGoAnalysisFactsExport  = DebugKeyGoAnalysisFacts + "/export"
+	DebugKeyGoAnalysisFactsInherit = DebugKeyGoAnalysisFacts + "/inherit"
+)
+
+const (
+	DebugKeyGoCritic  = "gocritic"
+	DebugKeyMegacheck = "megacheck"
+	DebugKeyNolint    = "nolint"
+	DebugKeyRevive    = "revive"
+)
+
 func getEnabledDebugs() map[string]bool {
 	ret := map[string]bool{}
-	debugVar := os.Getenv("GL_DEBUG")
+	debugVar := os.Getenv(envDebug)
 	if debugVar == "" {
 		return ret
 	}
diff --git a/pkg/logutils/stderr_log.go b/pkg/logutils/stderr_log.go
index b87060d6..a68215e7 100644
--- a/pkg/logutils/stderr_log.go
+++ b/pkg/logutils/stderr_log.go
@@ -10,13 +10,20 @@ import (
 	"github.com/golangci/golangci-lint/pkg/exitcodes"
 )
 
+const (
+	// envLogLevel values: "error", "err", "warning", "warn","info"
+	envLogLevel = "LOG_LEVEL"
+	// envLogTimestamp value: "1"
+	envLogTimestamp = "LOG_TIMESTAMP"
+)
+
 type StderrLog struct {
 	name   string
 	logger *logrus.Logger
 	level  LogLevel
 }
 
-var _ Log = NewStderrLog("")
+var _ Log = NewStderrLog(DebugKeyEmpty)
 
 func NewStderrLog(name string) *StderrLog {
 	sl := &StderrLog{
@@ -25,7 +32,7 @@ func NewStderrLog(name string) *StderrLog {
 		level:  LogLevelWarn,
 	}
 
-	switch os.Getenv("LOG_LEVEL") {
+	switch os.Getenv(envLogLevel) {
 	case "error", "err":
 		sl.logger.SetLevel(logrus.ErrorLevel)
 	case "warning", "warn":
@@ -41,7 +48,7 @@ func NewStderrLog(name string) *StderrLog {
 		DisableTimestamp:          true, // `INFO[0007] msg` -> `INFO msg`
 		EnvironmentOverrideColors: true,
 	}
-	if os.Getenv("LOG_TIMESTAMP") == "1" {
+	if os.Getenv(envLogTimestamp) == "1" {
 		formatter.DisableTimestamp = false
 		formatter.FullTimestamp = true
 		formatter.TimestampFormat = time.StampMilli
diff --git a/pkg/printers/tab_test.go b/pkg/printers/tab_test.go
index abef2a22..882699ef 100644
--- a/pkg/printers/tab_test.go
+++ b/pkg/printers/tab_test.go
@@ -46,7 +46,7 @@ func TestTab_Print(t *testing.T) {
 
 	buf := new(bytes.Buffer)
 
-	printer := NewTab(true, logutils.NewStderrLog(""), buf)
+	printer := NewTab(true, logutils.NewStderrLog(logutils.DebugKeyEmpty), buf)
 
 	err := printer.Print(context.Background(), issues)
 	require.NoError(t, err)
diff --git a/pkg/printers/text_test.go b/pkg/printers/text_test.go
index 06e87214..18f7c272 100644
--- a/pkg/printers/text_test.go
+++ b/pkg/printers/text_test.go
@@ -46,7 +46,7 @@ func TestText_Print(t *testing.T) {
 
 	buf := new(bytes.Buffer)
 
-	printer := NewText(true, false, true, logutils.NewStderrLog(""), buf)
+	printer := NewText(true, false, true, logutils.NewStderrLog(logutils.DebugKeyEmpty), buf)
 
 	err := printer.Print(context.Background(), issues)
 	require.NoError(t, err)
diff --git a/pkg/result/processors/autogenerated_exclude.go b/pkg/result/processors/autogenerated_exclude.go
index a11b68f7..f75ebaf5 100644
--- a/pkg/result/processors/autogenerated_exclude.go
+++ b/pkg/result/processors/autogenerated_exclude.go
@@ -12,7 +12,7 @@ import (
 	"github.com/golangci/golangci-lint/pkg/result"
 )
 
-var autogenDebugf = logutils.Debug("autogen_exclude")
+var autogenDebugf = logutils.Debug(logutils.DebugKeyAutogenExclude)
 
 type ageFileSummary struct {
 	isGenerated bool
diff --git a/pkg/result/processors/diff.go b/pkg/result/processors/diff.go
index 65e01785..67104bab 100644
--- a/pkg/result/processors/diff.go
+++ b/pkg/result/processors/diff.go
@@ -12,6 +12,8 @@ import (
 	"github.com/golangci/golangci-lint/pkg/result"
 )
 
+const envGolangciDiffProcessorPatch = "GOLANGCI_DIFF_PROCESSOR_PATCH"
+
 type Diff struct {
 	onlyNew       bool
 	fromRev       string
@@ -28,7 +30,7 @@ func NewDiff(onlyNew bool, fromRev, patchFilePath string, wholeFiles bool) *Diff
 		fromRev:       fromRev,
 		patchFilePath: patchFilePath,
 		wholeFiles:    wholeFiles,
-		patch:         os.Getenv("GOLANGCI_DIFF_PROCESSOR_PATCH"),
+		patch:         os.Getenv(envGolangciDiffProcessorPatch),
 	}
 }
 
diff --git a/pkg/result/processors/max_from_linter_test.go b/pkg/result/processors/max_from_linter_test.go
index 7f5c9bca..03c49ad1 100644
--- a/pkg/result/processors/max_from_linter_test.go
+++ b/pkg/result/processors/max_from_linter_test.go
@@ -8,7 +8,7 @@ import (
 )
 
 func TestMaxFromLinter(t *testing.T) {
-	p := NewMaxFromLinter(1, logutils.NewStderrLog(""), &config.Config{})
+	p := NewMaxFromLinter(1, logutils.NewStderrLog(logutils.DebugKeyEmpty), &config.Config{})
 	gosimple := newFromLinterIssue("gosimple")
 	gofmt := newFromLinterIssue("gofmt")
 	processAssertSame(t, p, gosimple)  // ok
diff --git a/pkg/result/processors/max_same_issues_test.go b/pkg/result/processors/max_same_issues_test.go
index cda09513..a85826f3 100644
--- a/pkg/result/processors/max_same_issues_test.go
+++ b/pkg/result/processors/max_same_issues_test.go
@@ -9,7 +9,7 @@ import (
 )
 
 func TestMaxSameIssues(t *testing.T) {
-	p := NewMaxSameIssues(1, logutils.NewStderrLog(""), &config.Config{})
+	p := NewMaxSameIssues(1, logutils.NewStderrLog(logutils.DebugKeyEmpty), &config.Config{})
 	i1 := result.Issue{
 		Text: "1",
 	}
diff --git a/pkg/result/processors/nolint.go b/pkg/result/processors/nolint.go
index 96104eab..492dfd72 100644
--- a/pkg/result/processors/nolint.go
+++ b/pkg/result/processors/nolint.go
@@ -16,7 +16,7 @@ import (
 	"github.com/golangci/golangci-lint/pkg/result"
 )
 
-var nolintDebugf = logutils.Debug("nolint")
+var nolintDebugf = logutils.Debug(logutils.DebugKeyNolint)
 var nolintRe = regexp.MustCompile(`^nolint( |:|$)`)
 
 type ignoredRange struct {
diff --git a/pkg/result/processors/severity_rules_test.go b/pkg/result/processors/severity_rules_test.go
index fdb874d1..b7407b53 100644
--- a/pkg/result/processors/severity_rules_test.go
+++ b/pkg/result/processors/severity_rules_test.go
@@ -14,7 +14,7 @@ import (
 
 func TestSeverityRulesMultiple(t *testing.T) {
 	lineCache := fsutils.NewLineCache(fsutils.NewFileCache())
-	log := report.NewLogWrapper(logutils.NewStderrLog(""), &report.Data{})
+	log := report.NewLogWrapper(logutils.NewStderrLog(logutils.DebugKeyEmpty), &report.Data{})
 	p := NewSeverityRules("error", []SeverityRule{
 		{
 			Severity: "info",
@@ -134,7 +134,7 @@ func TestSeverityRulesText(t *testing.T) {
 
 func TestSeverityRulesOnlyDefault(t *testing.T) {
 	lineCache := fsutils.NewLineCache(fsutils.NewFileCache())
-	log := report.NewLogWrapper(logutils.NewStderrLog(""), &report.Data{})
+	log := report.NewLogWrapper(logutils.NewStderrLog(logutils.DebugKeyEmpty), &report.Data{})
 	p := NewSeverityRules("info", []SeverityRule{}, lineCache, log)
 
 	cases := []issueTestCase{
diff --git a/test/enabled_linters_test.go b/test/enabled_linters_test.go
index f5b8839c..15a7d768 100644
--- a/test/enabled_linters_test.go
+++ b/test/enabled_linters_test.go
@@ -13,7 +13,7 @@ import (
 //nolint:funlen
 func TestEnabledLinters(t *testing.T) {
 	// require to display the message "Active x linters: [x,y]"
-	t.Setenv("GL_TEST_RUN", "1")
+	t.Setenv(lintersdb.EnvTestRun, "1")
 
 	cases := []struct {
 		name           string
diff --git a/test/fix_test.go b/test/fix_test.go
index 1eeb1fef..bccf620f 100644
--- a/test/fix_test.go
+++ b/test/fix_test.go
@@ -11,13 +11,16 @@ import (
 	"github.com/golangci/golangci-lint/test/testshared"
 )
 
+// value: "1"
+const envKeepTempFiles = "GL_KEEP_TEMP_FILES"
+
 func TestFix(t *testing.T) {
 	testshared.SkipOnWindows(t)
 
 	tmpDir := filepath.Join(testdataDir, "fix.tmp")
 	_ = os.RemoveAll(tmpDir) // cleanup previous runs
 
-	if os.Getenv("GL_KEEP_TEMP_FILES") == "1" {
+	if os.Getenv(envKeepTempFiles) == "1" {
 		t.Logf("Temp dir for fix test: %s", tmpDir)
 	} else {
 		t.Cleanup(func() { _ = os.RemoveAll(tmpDir) })
diff --git a/test/linters_test.go b/test/linters_test.go
index 466e983e..be705a13 100644
--- a/test/linters_test.go
+++ b/test/linters_test.go
@@ -55,7 +55,7 @@ func testSourcesFromDir(t *testing.T, dir string) {
 	err = os.Chdir(dir)
 	require.NoError(t, err)
 
-	log := logutils.NewStderrLog("test")
+	log := logutils.NewStderrLog(logutils.DebugKeyTest)
 	log.SetLevel(logutils.LogLevelInfo)
 
 	for _, source := range sources {
diff --git a/test/testshared/runner.go b/test/testshared/runner.go
index 1a6befed..70e2533b 100644
--- a/test/testshared/runner.go
+++ b/test/testshared/runner.go
@@ -17,6 +17,13 @@ import (
 	"github.com/golangci/golangci-lint/pkg/logutils"
 )
 
+const (
+	// value: "1"
+	envKeepTempFiles = "GL_KEEP_TEMP_FILES"
+	// value: "true"
+	envGolangciLintInstalled = "GOLANGCI_LINT_INSTALLED"
+)
+
 type RunnerBuilder struct {
 	tb  testing.TB
 	log logutils.Log
@@ -35,7 +42,7 @@ type RunnerBuilder struct {
 func NewRunnerBuilder(tb testing.TB) *RunnerBuilder {
 	tb.Helper()
 
-	log := logutils.NewStderrLog("test")
+	log := logutils.NewStderrLog(logutils.DebugKeyTest)
 	log.SetLevel(logutils.LogLevelInfo)
 
 	return &RunnerBuilder{
@@ -89,7 +96,7 @@ func (b *RunnerBuilder) WithConfig(cfg string) *RunnerBuilder {
 
 	cfgPath := cfgFile.Name()
 	b.tb.Cleanup(func() {
-		if os.Getenv("GL_KEEP_TEMP_FILES") != "1" {
+		if os.Getenv(envKeepTempFiles) != "1" {
 			_ = os.Remove(cfgPath)
 		}
 	})
@@ -334,7 +341,7 @@ func (r *RunnerResult) ExpectHasIssue(issueText string) *RunnerResult {
 func InstallGolangciLint(tb testing.TB) string {
 	tb.Helper()
 
-	if os.Getenv("GOLANGCI_LINT_INSTALLED") != "true" {
+	if os.Getenv(envGolangciLintInstalled) != "true" {
 		cmd := exec.Command("make", "-C", "..", "build")
 
 		output, err := cmd.CombinedOutput()