diff -pruN 2.1.0-1/context.go 2.2.0-1/context.go
--- 2.1.0-1/context.go	2024-04-24 11:23:31.000000000 +0000
+++ 2.2.0-1/context.go	2025-05-22 07:55:43.000000000 +0000
@@ -57,7 +57,8 @@ func (c *Context) GetLogger(name string,
 	defer c.modulesMutex.Unlock()
 
 	return Logger{
-		impl: c.getLoggerModule(name, tags),
+		impl:      c.getLoggerModule(name, tags),
+		callDepth: defaultCallDepth,
 	}
 }
 
diff -pruN 2.1.0-1/debian/changelog 2.2.0-1/debian/changelog
--- 2.1.0-1/debian/changelog	2024-07-07 12:45:13.000000000 +0000
+++ 2.2.0-1/debian/changelog	2025-09-29 13:04:00.000000000 +0000
@@ -1,3 +1,13 @@
+golang-github-juju-loggo (2.2.0-1) unstable; urgency=medium
+
+  * New upstream release
+  * d/control:
+    - Update Standards-Version to 4.7.2 (no changes needed)
+    - Drop redundant Rules-Requires-Root
+  * Update years in d/copyright
+
+ -- Mathias Gibbens <gibmat@debian.org>  Mon, 29 Sep 2025 13:04:00 +0000
+
 golang-github-juju-loggo (2.1.0-1) unstable; urgency=medium
 
   * New upstream release
diff -pruN 2.1.0-1/debian/control 2.2.0-1/debian/control
--- 2.1.0-1/debian/control	2024-07-07 12:43:21.000000000 +0000
+++ 2.2.0-1/debian/control	2025-09-29 13:03:17.000000000 +0000
@@ -9,11 +9,10 @@ Build-Depends: debhelper-compat (= 13),
                golang-any,
                golang-github-juju-ansiterm-dev,
                golang-gopkg-check.v1-dev
-Standards-Version: 4.7.0
+Standards-Version: 4.7.2
 Vcs-Browser: https://salsa.debian.org/go-team/packages/golang-github-juju-loggo
 Vcs-Git: https://salsa.debian.org/go-team/packages/golang-github-juju-loggo.git
 Homepage: https://github.com/juju/loggo
-Rules-Requires-Root: no
 XS-Go-Import-Path: github.com/juju/loggo
 
 Package: golang-github-juju-loggo-dev
diff -pruN 2.1.0-1/debian/copyright 2.2.0-1/debian/copyright
--- 2.1.0-1/debian/copyright	2024-07-07 12:42:13.000000000 +0000
+++ 2.2.0-1/debian/copyright	2025-09-29 13:02:34.000000000 +0000
@@ -9,7 +9,7 @@ License: LGPL-3.0-with-exception
 Files: debian/*
 Copyright:
  Copyright 2018-2021 Alexandre Viau <aviau@debian.org>
- Copyright 2021-2024 Mathias Gibbens
+ Copyright 2021-2025 Mathias Gibbens
 License: LGPL-3.0-with-exception
 Comment: Debian packaging is licensed under the same terms as upstream
 
diff -pruN 2.1.0-1/helper.go 2.2.0-1/helper.go
--- 2.1.0-1/helper.go	1970-01-01 00:00:00.000000000 +0000
+++ 2.2.0-1/helper.go	2025-05-22 07:55:43.000000000 +0000
@@ -0,0 +1,63 @@
+// Copyright 2025 Canonical Ltd.
+// Licensed under the LGPLv3, see LICENCE file for details.
+
+package loggo
+
+import (
+	"runtime"
+	"sync"
+)
+
+var (
+	helperMutex sync.RWMutex
+	helpers     map[uintptr]struct{}
+)
+
+// Helper passed 1 marks the caller as a helper function and will skip it when
+// capturing the callsite location.
+func Helper(skip int) {
+	helper(skip + 1)
+}
+
+func helper(skip int) {
+	callers := [1]uintptr{}
+	if runtime.Callers(skip+2, callers[:]) == 0 {
+		panic("failed to get caller information")
+	}
+	pc := callers[0]
+	helperMutex.RLock()
+	if _, ok := helpers[pc]; ok {
+		helperMutex.RUnlock()
+		return
+	}
+	helperMutex.RUnlock()
+	helperMutex.Lock()
+	defer helperMutex.Unlock()
+	if helpers == nil {
+		helpers = make(map[uintptr]struct{})
+	}
+	helpers[pc] = struct{}{}
+}
+
+// caller behaves like runtime.Caller but skips functions marked by helper.
+func caller(skip int) (uintptr, string, int, bool) {
+	pc := [8]uintptr{}
+	n := runtime.Callers(skip+2, pc[:])
+	if n == 0 {
+		return 0, "", 0, false
+	}
+	helperMutex.RLock()
+	pcs := pc[:]
+	for i := n - 1; i >= 0; i-- {
+		if _, ok := helpers[pc[i]]; ok {
+			pcs = pc[i:]
+			break
+		}
+	}
+	helperMutex.RUnlock()
+	frames := runtime.CallersFrames(pcs)
+	if frame, ok := frames.Next(); ok {
+		return frame.PC, frame.File, frame.Line, true
+	}
+	return 0, "", 0, false
+}
diff -pruN 2.1.0-1/logger.go 2.2.0-1/logger.go
--- 2.1.0-1/logger.go	2024-04-24 11:23:31.000000000 +0000
+++ 2.2.0-1/logger.go	2025-05-22 07:55:43.000000000 +0000
@@ -5,11 +5,16 @@ package loggo
 
 import (
 	"fmt"
-	"runtime"
 	"strings"
 	"time"
 )
 
+const (
+	// defaultCallDepth is the default number of stack frames to ascend to
+	// find the caller.
+	defaultCallDepth = 2
+)
+
 // A Logger represents a logging module. It has an associated logging
 // level which can be changed; messages of lesser severity will
 // be dropped. Loggers have a hierarchical relationship - see
@@ -20,6 +25,9 @@ import (
 type Logger struct {
 	impl   *module
 	labels Labels
+
+	// CallDepth is the number of stack frames to ascend to find the caller.
+	callDepth int
 }
 
 // WithLabels returns a logger whose module is the same as this logger and
@@ -40,6 +48,14 @@ func (logger Logger) WithLabels(labels L
 	return result
 }
 
+// WithCallDepth returns a logger whose call depth is set to the specified
+// value.
+func (logger Logger) WithCallDepth(callDepth int) Logger {
+	result := logger
+	result.callDepth = callDepth
+	return result
+}
+
 func (logger Logger) getModule() *module {
 	if logger.impl == nil {
 		return defaultContext.root
@@ -59,7 +75,10 @@ func (logger Logger) Root() Logger {
 // "a.b.c" is "a.b".
 // The Parent of the root logger is still the root logger.
 func (logger Logger) Parent() Logger {
-	return Logger{impl: logger.getModule().parent}
+	return Logger{
+		impl:      logger.getModule().parent,
+		callDepth: defaultCallDepth,
+	}
 }
 
 // Child returns the Logger whose module name is the composed of this
@@ -156,7 +175,11 @@ func (logger Logger) SetLogLevel(level L
 // Note that the writers may also filter out messages that
 // are less than their registered minimum severity level.
 func (logger Logger) Logf(level Level, message string, args ...interface{}) {
-	logger.LogCallf(2, level, message, args...)
+	logger.logf(level, message, args...)
+}
+
+func (logger Logger) logf(level Level, message string, args ...interface{}) {
+	logger.logCallf(logger.callDepth, level, message, nil, args...)
 }
 
 // LogWithlabelsf logs a printf-formatted message at the given level with extra
@@ -165,7 +188,7 @@ func (logger Logger) Logf(level Level, m
 // of the logger. Note that the writers may also filter out messages that are
 // less than their registered minimum severity level.
 func (logger Logger) LogWithLabelsf(level Level, message string, extraLabels map[string]string, args ...interface{}) {
-	logger.logCallf(2, level, message, extraLabels, args...)
+	logger.logCallf(logger.callDepth-1, level, message, extraLabels, args...)
 }
 
 // LogCallf logs a printf-formatted message at the given level.
@@ -176,7 +199,7 @@ func (logger Logger) LogWithLabelsf(leve
 // Note that the writers may also filter out messages that
 // are less than their registered minimum severity level.
 func (logger Logger) LogCallf(calldepth int, level Level, message string, args ...interface{}) {
-	logger.logCallf(calldepth+1, level, message, nil, args...)
+	logger.logCallf(calldepth, level, message, nil, args...)
 }
 
 // logCallf is a private method for logging a printf-formatted message at the
@@ -190,7 +213,7 @@ func (logger Logger) logCallf(calldepth
 	now := time.Now() // get this early.
 	// Param to Caller is the call depth.  Since this method is called from
 	// the Logger methods, we want the place that those were called from.
-	_, file, line, ok := runtime.Caller(calldepth + 1)
+	_, file, line, ok := caller(calldepth + 1)
 	if !ok {
 		file = "???"
 		line = 0
@@ -221,7 +244,7 @@ func (logger Logger) logCallf(calldepth
 	if len(module.tags) > 0 {
 		entry.Labels[LoggerTags] = strings.Join(module.tags, ",")
 	}
-	for k, v := range logger.impl.labels {
+	for k, v := range module.labels {
 		entry.Labels[k] = v
 	}
 	for k, v := range logger.labels {
@@ -236,38 +259,38 @@ func (logger Logger) logCallf(calldepth
 
 // Criticalf logs the printf-formatted message at critical level.
 func (logger Logger) Criticalf(message string, args ...interface{}) {
-	logger.Logf(CRITICAL, message, args...)
+	logger.logf(CRITICAL, message, args...)
 }
 
 // Errorf logs the printf-formatted message at error level.
 func (logger Logger) Errorf(message string, args ...interface{}) {
-	logger.Logf(ERROR, message, args...)
+	logger.logf(ERROR, message, args...)
 }
 
 // Warningf logs the printf-formatted message at warning level.
 func (logger Logger) Warningf(message string, args ...interface{}) {
-	logger.Logf(WARNING, message, args...)
+	logger.logf(WARNING, message, args...)
 }
 
 // Infof logs the printf-formatted message at info level.
 func (logger Logger) Infof(message string, args ...interface{}) {
-	logger.Logf(INFO, message, args...)
+	logger.logf(INFO, message, args...)
 }
 
 // InfoWithLabelsf logs the printf-formatted message at info level with extra
 // labels.
 func (logger Logger) InfoWithLabelsf(message string, extraLabels map[string]string, args ...interface{}) {
-	logger.LogWithLabelsf(INFO, message, extraLabels, args...)
+	logger.logCallf(logger.callDepth, INFO, message, extraLabels, args...)
 }
 
 // Debugf logs the printf-formatted message at debug level.
 func (logger Logger) Debugf(message string, args ...interface{}) {
-	logger.Logf(DEBUG, message, args...)
+	logger.logf(DEBUG, message, args...)
 }
 
 // Tracef logs the printf-formatted message at trace level.
 func (logger Logger) Tracef(message string, args ...interface{}) {
-	logger.Logf(TRACE, message, args...)
+	logger.logf(TRACE, message, args...)
 }
 
 // IsLevelEnabled returns whether debugging is enabled
@@ -305,3 +328,9 @@ func (logger Logger) IsDebugEnabled() bo
 func (logger Logger) IsTraceEnabled() bool {
 	return logger.IsLevelEnabled(TRACE)
 }
+
+// Helper marks the caller as a helper function and will skip it when capturing
+// the callsite location.
+func (logger Logger) Helper() {
+	helper(2)
+}
diff -pruN 2.1.0-1/logger_test.go 2.2.0-1/logger_test.go
--- 2.1.0-1/logger_test.go	2024-04-24 11:23:31.000000000 +0000
+++ 2.2.0-1/logger_test.go	2025-05-22 07:55:43.000000000 +0000
@@ -18,7 +18,7 @@ func (*LoggerSuite) SetUpTest(c *gc.C) {
 }
 
 func (s *LoggerSuite) TestRootLogger(c *gc.C) {
-	root := loggo.Logger{}
+	root := loggo.Logger{}.WithCallDepth(2)
 	c.Check(root.Name(), gc.Equals, "<root>")
 	c.Check(root.LogLevel(), gc.Equals, loggo.WARNING)
 	c.Check(root.IsErrorEnabled(), gc.Equals, true)
diff -pruN 2.1.0-1/logging_test.go 2.2.0-1/logging_test.go
--- 2.1.0-1/logging_test.go	2024-04-24 11:23:31.000000000 +0000
+++ 2.2.0-1/logging_test.go	2025-05-22 07:55:43.000000000 +0000
@@ -63,21 +63,29 @@ func (s *LoggingSuite) TestLoggingLimitW
 }
 
 func (s *LoggingSuite) TestLocationCapture(c *gc.C) {
-	s.logger.Criticalf("critical message") //tag critical-location
-	s.logger.Errorf("error message")       //tag error-location
-	s.logger.Warningf("warning message")   //tag warning-location
-	s.logger.Infof("info message")         //tag info-location
-	s.logger.Debugf("debug message")       //tag debug-location
-	s.logger.Tracef("trace message")       //tag trace-location
+	s.helperInfof(c, "helper message")                             //tag helper-location
+	s.logger.Criticalf("critical message")                         //tag critical-location
+	s.logger.Errorf("error message")                               //tag error-location
+	s.logger.Warningf("warning message")                           //tag warning-location
+	s.logger.Infof("info message")                                 //tag info-location
+	s.logger.Debugf("debug message")                               //tag debug-location
+	s.logger.Tracef("trace message")                               //tag trace-location
+	s.logger.Logf(loggo.INFO, "logf msg")                          //tag logf-location
+	s.logger.LogCallf(1, loggo.INFO, "logcallf msg")               //tag logcallf-location
+	s.logger.LogWithLabelsf(loggo.INFO, "logwithlabelsf msg", nil) //tag logwithlabelsf-location
 
 	log := s.writer.Log()
 	tags := []string{
+		"helper-location",
 		"critical-location",
 		"error-location",
 		"warning-location",
 		"info-location",
 		"debug-location",
 		"trace-location",
+		"logf-location",
+		"logcallf-location",
+		"logwithlabelsf-location",
 	}
 	c.Assert(log, gc.HasLen, len(tags))
 	for x := range tags {
@@ -85,6 +93,11 @@ func (s *LoggingSuite) TestLocationCaptu
 	}
 }
 
+func (s *LoggingSuite) helperInfof(c *gc.C, format string, args ...any) {
+	s.logger.Helper()
+	s.logger.Infof(format, args...)
+}
+
 func (s *LoggingSuite) TestLogDoesntLogWeirdLevels(c *gc.C) {
 	s.logger.Logf(loggo.UNSPECIFIED, "message")
 	c.Assert(s.writer.Log(), gc.HasLen, 0)
diff -pruN 2.1.0-1/util_test.go 2.2.0-1/util_test.go
--- 2.1.0-1/util_test.go	2024-04-24 11:23:31.000000000 +0000
+++ 2.2.0-1/util_test.go	2025-05-22 07:55:43.000000000 +0000
@@ -20,8 +20,9 @@ func init() {
 
 func assertLocation(c *gc.C, msg loggo.Entry, tag string) {
 	loc := location(tag)
-	c.Assert(msg.Filename, gc.Equals, loc.file)
-	c.Assert(msg.Line, gc.Equals, loc.line)
+	c.Check(fmt.Sprintf("%s:%d", msg.Filename, msg.Line), gc.Equals,
+		fmt.Sprintf("%s:%d", loc.file, loc.line),
+		gc.Commentf("tag=%s", tag))
 }
 
 // All this location stuff is to avoid having hard coded line numbers
