~rjarry/aerc-devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
8 2

[PATCH aerc v2 0/5] log-file diet

Details
Message ID
<20221127123203.145179-1-robin@jarry.cc>
DKIM signature
pass
Download raw message
What week is it? It is also logging week.

aerc outputs too much information for most people. Define clear rules
for what logging levels should be used.

Changes since v2:

- renamed logging package to log.

Robin Jarry (5):
  logging: add new trace log level
  msgviewer: add logs to display pager and filter commands
  logging: use local time for logging
  logging: homogenize levels
  logging: rename package to log

 .gitignore                       |  1 -
 CONTRIBUTING.md                  | 17 +++++++
 README.md                        |  2 +-
 aerc.go                          | 28 +++++------
 commands/account/compose.go      |  4 +-
 commands/account/export-mbox.go  | 16 +++---
 commands/account/import-mbox.go  | 16 +++---
 commands/account/recover.go      |  4 +-
 commands/account/search.go       |  6 +--
 commands/compose/attach.go       | 28 +++++------
 commands/compose/postpone.go     |  8 +--
 commands/compose/send.go         |  8 +--
 commands/exec.go                 |  4 +-
 commands/history.go              |  4 +-
 commands/msg/archive.go          |  4 +-
 commands/msg/envelope.go         |  4 +-
 commands/msg/forward.go          | 14 +++---
 commands/msg/invite.go           |  4 +-
 commands/msg/pipe.go             | 10 ++--
 commands/msg/recall.go           | 10 ++--
 commands/msg/reply.go            | 10 ++--
 commands/msg/unsubscribe.go      |  6 +--
 commands/msgview/save.go         |  4 +-
 commands/util.go                 |  4 +-
 completer/completer.go           | 10 ++--
 config/accounts.go               |  6 +--
 config/binds.go                  |  8 +--
 config/compose.go                |  4 +-
 config/filters.go                |  4 +-
 config/general.go                | 22 ++++-----
 config/openers.go                |  4 +-
 config/statusline.go             |  4 +-
 config/templates.go              |  4 +-
 config/triggers.go               |  6 +--
 config/ui.go                     |  6 +--
 config/viewer.go                 |  4 +-
 doc/aerc-config.5.scd            |  6 +--
 doc/aerc.1.scd                   |  2 +-
 lib/attachment.go                |  4 +-
 lib/crypto/gpg/gpgbin/gpgbin.go  |  8 +--
 lib/crypto/pgp/pgp.go            |  4 +-
 lib/messageview.go               |  6 +--
 lib/msgstore.go                  |  6 +--
 lib/open.go                      |  6 +--
 lib/parse/ansi.go                |  6 +--
 lib/socket.go                    | 38 +++++++-------
 lib/threadbuilder.go             |  6 +--
 lib/ui/textinput.go              |  4 +-
 {logging => log}/logger.go       | 21 ++++++--
 {logging => log}/panic-logger.go |  2 +-
 widgets/account.go               | 18 +++----
 widgets/aerc.go                  | 10 ++--
 widgets/compose.go               | 30 +++++------
 widgets/dirlist.go               |  6 +--
 widgets/dirtree.go               |  6 +--
 widgets/listbox.go               |  4 +-
 widgets/msglist.go               |  4 +-
 widgets/msgviewer.go             | 22 +++++----
 widgets/spinner.go               |  4 +-
 widgets/status.go                |  4 +-
 widgets/terminal.go              |  4 +-
 worker/imap/cache.go             | 35 ++++++-------
 worker/imap/checkmail.go         |  4 +-
 worker/imap/connect.go           |  8 +--
 worker/imap/fetch.go             | 12 ++---
 worker/imap/flags.go             |  4 +-
 worker/imap/idler.go             |  8 +--
 worker/imap/list.go              |  8 +--
 worker/imap/observer.go          |  4 +-
 worker/imap/open.go              | 16 +++---
 worker/imap/worker.go            | 12 ++---
 worker/lib/parse.go              |  4 +-
 worker/maildir/search.go         |  6 +--
 worker/maildir/worker.go         | 85 ++++++++++++++++----------------
 worker/mbox/worker.go            | 30 +++++------
 worker/notmuch/eventhandlers.go  |  4 +-
 worker/notmuch/lib/database.go   | 16 +++---
 worker/notmuch/worker.go         | 72 +++++++++++++--------------
 worker/types/thread.go           |  4 +-
 worker/types/worker.go           | 18 +++----
 80 files changed, 456 insertions(+), 423 deletions(-)
 rename {logging => log}/logger.go (82%)
 rename {logging => log}/panic-logger.go (98%)

-- 
2.38.1

[PATCH aerc v2 1/5] logging: add new trace log level

Details
Message ID
<20221127123203.145179-2-robin@jarry.cc>
In-Reply-To
<20221127123203.145179-1-robin@jarry.cc> (view parent)
DKIM signature
pass
Download raw message
Patch: +19 -4
We need more logging granularity.

Signed-off-by: Robin Jarry <robin@jarry.cc>
---
 doc/aerc-config.5.scd |  6 +++---
 logging/logger.go     | 17 ++++++++++++++++-
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index 9df2ad4996b0..fcb3b903d7da 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -54,9 +54,9 @@ These options are configured in the *[general]* section of _aerc.conf_.

*log-level*
	Only log messages above the specified level to *log-file*. Supported
	levels are: _debug_, _info_, _warn_ and _error_. When redirecting aerc's
	output to a file using _>_ shell redirection, this setting is ignored
	and the log level is forced to _debug_.
	levels are: _trace_, _debug_, _info_, _warn_ and _error_. When
	redirecting aerc's output to a file using _>_ shell redirection, this
	setting is ignored and the log level is forced to _debug_.

	Default: _info_

diff --git a/logging/logger.go b/logging/logger.go
index 47dd3ba60451..da548c07546a 100644
--- a/logging/logger.go
+++ b/logging/logger.go
@@ -11,6 +11,7 @@ import (
type LogLevel int

const (
	TRACE LogLevel = 5
	DEBUG LogLevel = 10
	INFO  LogLevel = 20
	WARN  LogLevel = 30
@@ -18,17 +19,19 @@ const (
)

var (
	trace    *log.Logger
	dbg      *log.Logger
	info     *log.Logger
	warn     *log.Logger
	err      *log.Logger
	minLevel LogLevel = DEBUG
	minLevel LogLevel = TRACE
)

func Init(file *os.File, level LogLevel) {
	minLevel = level
	flags := log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile | log.LUTC
	if file != nil {
		trace = log.New(file, "TRACE ", flags)
		dbg = log.New(file, "DEBUG ", flags)
		info = log.New(file, "INFO  ", flags)
		warn = log.New(file, "WARN  ", flags)
@@ -38,6 +41,8 @@ func Init(file *os.File, level LogLevel) {

func ParseLevel(value string) (LogLevel, error) {
	switch strings.ToLower(value) {
	case "trace":
		return TRACE, nil
	case "debug":
		return DEBUG, nil
	case "info":
@@ -57,6 +62,16 @@ func ErrorLogger() *log.Logger {
	return err
}

func Tracef(message string, args ...interface{}) {
	if trace == nil || minLevel > TRACE {
		return
	}
	if len(args) > 0 {
		message = fmt.Sprintf(message, args...)
	}
	trace.Output(2, message) //nolint:errcheck // we can't do anything with what we log
}

func Debugf(message string, args ...interface{}) {
	if dbg == nil || minLevel > DEBUG {
		return
-- 
2.38.1

[PATCH aerc v2 2/5] msgviewer: add logs to display pager and filter commands

Details
Message ID
<20221127123203.145179-3-robin@jarry.cc>
In-Reply-To
<20221127123203.145179-1-robin@jarry.cc> (view parent)
DKIM signature
pass
Download raw message
Patch: +2 -0
That may be useful to debug some filter matchers.

Signed-off-by: Robin Jarry <robin@jarry.cc>
---
 widgets/msgviewer.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index ea28165ed75a..1cc2d6f567da 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -603,6 +603,8 @@ func NewPartViewer(acct *AccountView, conf *config.AercConfig,
			fmt.Sprintf("AERC_SUBJECT=%s", info.Envelope.Subject))
		filter.Env = append(filter.Env, fmt.Sprintf("AERC_FROM=%s",
			format.FormatAddresses(info.Envelope.From)))
		logging.Debugf("<%s> part=%v %s: %v | %v",
			info.Envelope.MessageId, curindex, mime, filter, pager)
		if pagerin, err = pager.StdinPipe(); err != nil {
			return nil, err
		}
-- 
2.38.1

[PATCH aerc v2 3/5] logging: use local time for logging

Details
Message ID
<20221127123203.145179-4-robin@jarry.cc>
In-Reply-To
<20221127123203.145179-1-robin@jarry.cc> (view parent)
DKIM signature
pass
Download raw message
Patch: +1 -1
I don't see a point in logging with UTC time. Also, it can be confusing
since this is not explicit in the date format.

Signed-off-by: Robin Jarry <robin@jarry.cc>
---
 logging/logger.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/logging/logger.go b/logging/logger.go
index da548c07546a..8dc4ef6b9dfe 100644
--- a/logging/logger.go
+++ b/logging/logger.go
@@ -29,7 +29,7 @@ var (

func Init(file *os.File, level LogLevel) {
	minLevel = level
	flags := log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile | log.LUTC
	flags := log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile
	if file != nil {
		trace = log.New(file, "TRACE ", flags)
		dbg = log.New(file, "DEBUG ", flags)
-- 
2.38.1

[PATCH aerc v2 4/5] logging: homogenize levels

Details
Message ID
<20221127123203.145179-5-robin@jarry.cc>
In-Reply-To
<20221127123203.145179-1-robin@jarry.cc> (view parent)
DKIM signature
pass
Download raw message
Patch: +110 -90
The main goal is to ensure that by default, the log file (if configured)
does not grow out of proportions. Most of the logging messages in aerc
are actually for debugging and/or trace purposes.

Define clear rules for logging levels. Enforce these rules everywhere.

After this patch, here is what the log file looks like after starting up
with a single account:

INFO  2022/11/24 20:26:16.147164 aerc.go:176: Starting up version 0.13.0-100-g683981479c60 (go1.18.7 amd64 linux)
INFO  2022/11/24 20:26:17.546448 account.go:254: [work] connected.

Signed-off-by: Robin Jarry <robin@jarry.cc>
---
 CONTRIBUTING.md                 | 17 +++++++++++++++++
 aerc.go                         |  4 ++--
 commands/account/export-mbox.go |  2 +-
 commands/account/import-mbox.go |  4 ++--
 commands/account/search.go      |  4 ++--
 commands/compose/attach.go      | 11 ++++-------
 commands/compose/postpone.go    |  2 +-
 commands/msg/forward.go         |  2 +-
 commands/msg/recall.go          |  4 ++--
 commands/msg/unsubscribe.go     |  4 ++--
 config/accounts.go              |  2 +-
 config/binds.go                 |  2 +-
 lib/attachment.go               |  2 +-
 lib/crypto/gpg/gpgbin/gpgbin.go |  2 +-
 lib/crypto/pgp/pgp.go           |  2 +-
 lib/msgstore.go                 |  2 +-
 lib/open.go                     |  2 +-
 lib/socket.go                   | 16 ++++++++++------
 lib/threadbuilder.go            |  2 +-
 widgets/account.go              | 12 ++++++------
 widgets/aerc.go                 |  2 +-
 widgets/compose.go              |  4 ++--
 widgets/dirlist.go              |  2 +-
 widgets/msgviewer.go            |  2 +-
 worker/imap/cache.go            | 13 +++++++------
 worker/imap/checkmail.go        |  2 +-
 worker/imap/fetch.go            |  6 +++---
 worker/imap/idler.go            |  2 +-
 worker/imap/list.go             |  4 ++--
 worker/imap/observer.go         |  2 +-
 worker/imap/open.go             | 10 +++++-----
 worker/imap/worker.go           |  6 +++---
 worker/maildir/search.go        |  2 +-
 worker/maildir/worker.go        | 21 +++++++++++----------
 worker/mbox/worker.go           |  6 +++---
 worker/notmuch/worker.go        |  2 +-
 worker/types/worker.go          | 16 ++++++++--------
 37 files changed, 110 insertions(+), 90 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4b93682f49c8..03c606ac7640 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -240,6 +240,23 @@ by running `make fmt`.

If gofumpt accepts your code it's most likely properly formatted.

### Logging

Aerc allows logging messages to a file. Either by redirecting the output to
a file (e.g. `aerc > log`), or by configuring `log-file` in ``aerc.conf`.
Logging messages are associated with a severity level, from lowest to highest:
`trace`, `debug`, `info`, `warn`, `error`.

Messages can be sent to the log file by using the following functions:

- `logging.Errorf()`: Use to report serious (but non-fatal) errors.
- `logging.Warnf()`: Use to report issues that do not affect normal use.
- `logging.Infof()`: Use to display important messages that may concern
  non-developers.
- `logging.Debugf()`: Use to display non-important messages, or debuging
  details.
- `logging.Tracef()`: Use to display only low level debugging traces.

### Man pages

All `doc/*.scd` files are written in the [scdoc][scdoc] format and compiled to
diff --git a/aerc.go b/aerc.go
index 09ddc43fa712..b74697680043 100644
--- a/aerc.go
+++ b/aerc.go
@@ -113,7 +113,7 @@ func usage(msg string) {
}

func setWindowTitle() {
	logging.Debugf("Parsing terminfo")
	logging.Tracef("Parsing terminfo")
	ti, err := terminfo.LoadFromEnv()
	if err != nil {
		logging.Warnf("Cannot get terminfo: %v", err)
@@ -125,7 +125,7 @@ func setWindowTitle() {
		return
	}

	logging.Infof("Setting terminal title")
	logging.Debugf("Setting terminal title")
	buf := new(bytes.Buffer)
	ti.Fprintf(buf, terminfo.ToStatusLine)
	fmt.Fprint(buf, "aerc")
diff --git a/commands/account/export-mbox.go b/commands/account/export-mbox.go
index b68e1cc55b24..f51608b904ad 100644
--- a/commands/account/export-mbox.go
+++ b/commands/account/export-mbox.go
@@ -117,7 +117,7 @@ func (ExportMbox) Execute(aerc *widgets.Aerc, args []string) error {
		}
		statusInfo := fmt.Sprintf("Exported %d of %d messages to %s.", ctr, len(store.Uids()), filename)
		aerc.PushStatus(statusInfo, 10*time.Second)
		logging.Infof(statusInfo)
		logging.Debugf(statusInfo)
	}()

	return nil
diff --git a/commands/account/import-mbox.go b/commands/account/import-mbox.go
index 5a8a2ee628e1..93408acadb4b 100644
--- a/commands/account/import-mbox.go
+++ b/commands/account/import-mbox.go
@@ -55,7 +55,7 @@ func (ImportMbox) Execute(aerc *widgets.Aerc, args []string) error {
	importFolder := func() {
		statusInfo := fmt.Sprintln("Importing", filename, "to folder", folder)
		aerc.PushStatus(statusInfo, 10*time.Second)
		logging.Infof(statusInfo)
		logging.Debugf(statusInfo)
		f, err := os.Open(filename)
		if err != nil {
			aerc.PushError(err.Error())
@@ -123,7 +123,7 @@ func (ImportMbox) Execute(aerc *widgets.Aerc, args []string) error {
			}
		}
		infoStr := fmt.Sprintf("%s: imported %d of %d sucessfully.", args[0], appended, len(messages))
		logging.Infof(infoStr)
		logging.Debugf(infoStr)
		aerc.SetStatus(infoStr)
	}

diff --git a/commands/account/search.go b/commands/account/search.go
index b4942bf54d5c..125cb5d7558b 100644
--- a/commands/account/search.go
+++ b/commands/account/search.go
@@ -44,7 +44,7 @@ func (SearchFilter) Execute(aerc *widgets.Aerc, args []string) error {
		cb := func(msg types.WorkerMessage) {
			if _, ok := msg.(*types.Done); ok {
				acct.SetStatus(statusline.FilterResult(strings.Join(args, " ")))
				logging.Infof("Filter results: %v", store.Uids())
				logging.Tracef("Filter results: %v", store.Uids())
			}
		}
		store.Sort(store.GetCurrentSortCriteria(), cb)
@@ -52,7 +52,7 @@ func (SearchFilter) Execute(aerc *widgets.Aerc, args []string) error {
		acct.SetStatus(statusline.Search("Searching..."))
		cb := func(uids []uint32) {
			acct.SetStatus(statusline.Search(strings.Join(args, " ")))
			logging.Infof("Search results: %v", uids)
			logging.Tracef("Search results: %v", uids)
			store.ApplySearch(uids)
			// TODO: Remove when stores have multiple OnUpdate handlers
			ui.Invalidate()
diff --git a/commands/compose/attach.go b/commands/compose/attach.go
index af5c023c1d35..de83ef0b1d78 100644
--- a/commands/compose/attach.go
+++ b/commands/compose/attach.go
@@ -52,16 +52,12 @@ func (a Attach) addPath(aerc *widgets.Aerc, path string) error {
		return err
	}

	logging.Debugf("attaching %s", path)

	attachments, err := filepath.Glob(path)
	if err != nil && errors.Is(err, filepath.ErrBadPattern) {
		logging.Warnf("failed to parse as globbing pattern: %v", err)
		attachments = []string{path}
	}

	logging.Debugf("filenames: %v", attachments)

	composer, _ := aerc.SelectedTabContent().(*widgets.Composer)
	for _, attach := range attachments {
		logging.Debugf("attaching '%s'", attach)
@@ -134,6 +130,7 @@ func (a Attach) openMenu(aerc *widgets.Aerc, args []string) error {
		_, err = picks.Seek(0, io.SeekStart)
		if err != nil {
			logging.Errorf("seek failed: %v", err)
			return
		}

		scanner := bufio.NewScanner(picks)
@@ -142,11 +139,11 @@ func (a Attach) openMenu(aerc *widgets.Aerc, args []string) error {
			if _, err := os.Stat(f); err != nil {
				continue
			}
			logging.Infof("File picker attaches: %v", f)
			logging.Tracef("File picker attaches: %v", f)
			err := a.addPath(aerc, f)
			if err != nil {
				logging.Errorf("attach failed "+
					"for file %s: %v", f, err)
				logging.Errorf(
					"attach failed for file %s: %v", f, err)
			}

		}
diff --git a/commands/compose/postpone.go b/commands/compose/postpone.go
index 7469b235a824..2572d8d5a479 100644
--- a/commands/compose/postpone.go
+++ b/commands/compose/postpone.go
@@ -47,7 +47,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {
		return errors.New("No Postpone location configured")
	}

	logging.Infof("Postponing mail")
	logging.Tracef("Postponing mail")

	header, err := composer.PrepareHeader()
	if err != nil {
diff --git a/commands/msg/forward.go b/commands/msg/forward.go
index ccfaa086171c..74ee6575282d 100644
--- a/commands/msg/forward.go
+++ b/commands/msg/forward.go
@@ -74,7 +74,7 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error {
	if err != nil {
		return err
	}
	logging.Infof("Forwarding email %s", msg.Envelope.MessageId)
	logging.Debugf("Forwarding email <%s>", msg.Envelope.MessageId)

	h := &mail.Header{}
	subject := "Fwd: " + msg.Envelope.Subject
diff --git a/commands/msg/recall.go b/commands/msg/recall.go
index b5c92f21c30f..eb8195f8937e 100644
--- a/commands/msg/recall.go
+++ b/commands/msg/recall.go
@@ -70,7 +70,7 @@ func (Recall) Execute(aerc *widgets.Aerc, args []string) error {
	if err != nil {
		return errors.Wrap(err, "Recall failed")
	}
	logging.Infof("Recalling message %s", msgInfo.Envelope.MessageId)
	logging.Debugf("Recalling message <%s>", msgInfo.Envelope.MessageId)

	composer, err := widgets.NewComposer(aerc, acct, aerc.Config(),
		acct.AccountConfig(), acct.Worker(), "", msgInfo.RFC822Headers,
@@ -200,7 +200,7 @@ func (Recall) Execute(aerc *widgets.Aerc, args []string) error {
					}
					bs, err := msg.BodyStructure().PartAtIndex(p)
					if err != nil {
						logging.Infof("cannot get PartAtIndex %v: %v", p, err)
						logging.Warnf("cannot get PartAtIndex %v: %v", p, err)
						continue
					}
					msg.FetchBodyPart(p, func(reader io.Reader) {
diff --git a/commands/msg/unsubscribe.go b/commands/msg/unsubscribe.go
index 022135ebd7e8..72c839fe1ae7 100644
--- a/commands/msg/unsubscribe.go
+++ b/commands/msg/unsubscribe.go
@@ -56,10 +56,10 @@ func (Unsubscribe) Execute(aerc *widgets.Aerc, args []string) error {
	if len(methods) == 0 {
		return fmt.Errorf("no methods found to unsubscribe")
	}
	logging.Infof("unsubscribe: found %d methods", len(methods))
	logging.Debugf("unsubscribe: found %d methods", len(methods))

	unsubscribe := func(method *url.URL) {
		logging.Infof("unsubscribe: trying to unsubscribe using %s", method.Scheme)
		logging.Debugf("unsubscribe: trying to unsubscribe using %s", method.Scheme)
		var err error
		switch strings.ToLower(method.Scheme) {
		case "mailto":
diff --git a/config/accounts.go b/config/accounts.go
index e168231f8601..b33bdf09ed8c 100644
--- a/config/accounts.go
+++ b/config/accounts.go
@@ -112,7 +112,7 @@ func (config *AercConfig) parseAccounts(root string, accts []string) error {
		}
	}

	logging.Infof("Parsing accounts configuration from %s", filename)
	logging.Debugf("Parsing accounts configuration from %s", filename)

	file, err := ini.Load(filename)
	if err != nil {
diff --git a/config/binds.go b/config/binds.go
index 4b32e6da0d6a..281aebf6881b 100644
--- a/config/binds.go
+++ b/config/binds.go
@@ -77,7 +77,7 @@ func (config *AercConfig) parseBinds(root string) error {
			return err
		}
	}
	logging.Infof("Parsing key bindings configuration from %s", filename)
	logging.Debugf("Parsing key bindings configuration from %s", filename)
	binds, err := ini.Load(filename)
	if err != nil {
		return err
diff --git a/lib/attachment.go b/lib/attachment.go
index bc29a5671946..e926dfa94bce 100644
--- a/lib/attachment.go
+++ b/lib/attachment.go
@@ -153,7 +153,7 @@ func SetUtf8Charset(origParams map[string]string) map[string]string {
	for k, v := range origParams {
		switch strings.ToLower(k) {
		case "charset":
			logging.Infof("substitute charset %s with utf-8", v)
			logging.Debugf("substitute charset %s with utf-8", v)
			params[k] = "utf-8"
		default:
			params[k] = v
diff --git a/lib/crypto/gpg/gpgbin/gpgbin.go b/lib/crypto/gpg/gpgbin/gpgbin.go
index 1e8c7dcd7814..d83c45fb2884 100644
--- a/lib/crypto/gpg/gpgbin/gpgbin.go
+++ b/lib/crypto/gpg/gpgbin/gpgbin.go
@@ -129,7 +129,7 @@ func parse(r io.Reader, md *models.MessageDetails) error {
		}
		if strings.HasPrefix(line, "[GNUPG:]") {
			msgCollecting = false
			logging.Debugf(line)
			logging.Tracef(line)
		}
		if msgCollecting {
			msgContent = append(msgContent, scanner.Bytes()...)
diff --git a/lib/crypto/pgp/pgp.go b/lib/crypto/pgp/pgp.go
index f5612eea7cd7..fd9d13eb470c 100644
--- a/lib/crypto/pgp/pgp.go
+++ b/lib/crypto/pgp/pgp.go
@@ -29,7 +29,7 @@ var (
)

func (m *Mail) Init() error {
	logging.Infof("Initializing PGP keyring")
	logging.Debugf("Initializing PGP keyring")
	err := os.MkdirAll(path.Join(xdg.DataHome(), "aerc"), 0o700)
	if err != nil {
		return fmt.Errorf("failed to create data directory: %w", err)
diff --git a/lib/msgstore.go b/lib/msgstore.go
index dfa251915c7d..4205ea109536 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -420,7 +420,7 @@ func (store *MessageStore) runThreadBuilder() {
	}
	if store.threadBuilderDebounce != nil {
		if store.threadBuilderDebounce.Stop() {
			logging.Infof("thread builder debounced")
			logging.Tracef("thread builder debounced")
		}
	}
	store.threadBuilderDebounce = time.AfterFunc(store.threadBuilderDelay, func() {
diff --git a/lib/open.go b/lib/open.go
index e091d913a9dd..9faa6d1021dc 100644
--- a/lib/open.go
+++ b/lib/open.go
@@ -46,7 +46,7 @@ func XDGOpenMime(
		args = append(args, uri)
	}

	logging.Infof("running command: %v", args)
	logging.Tracef("running command: %v", args)
	cmd := exec.Command(args[0], args[1:]...)
	out, err := cmd.CombinedOutput()
	logging.Debugf("command: %v exited. err=%v out=%s", args, err, out)
diff --git a/lib/socket.go b/lib/socket.go
index 4da3485b2032..1cfd0583e62a 100644
--- a/lib/socket.go
+++ b/lib/socket.go
@@ -28,7 +28,7 @@ func StartServer() (*AercServer, error) {
	if err := ConnectAndExec(""); err != nil {
		os.Remove(sockpath)
	}
	logging.Infof("Starting Unix server: %s", sockpath)
	logging.Debugf("Starting Unix server: %s", sockpath)
	l, err := net.Listen("unix", sockpath)
	if err != nil {
		return nil, err
@@ -41,9 +41,13 @@ func StartServer() (*AercServer, error) {
		for {
			conn, err := l.Accept()
			if err != nil {
				// TODO: Something more useful, in some cases, on wednesdays,
				// after 2 PM, I guess?
				logging.Errorf("Closing Unix server: %v", err)
				if !strings.Contains(err.Error(),
					"use of closed network connection") {
					// TODO: Something more useful, in some
					// cases, on wednesdays, after 2 PM,
					// I guess?
					logging.Errorf("Closing Unix server: %v", err)
				}
				return
			}
			go func() {
@@ -76,7 +80,7 @@ func (as *AercServer) handleClient(conn net.Conn) {
			logging.Errorf("failed to update deadline: %v", err)
		}
		msg := scanner.Text()
		logging.Debugf("unix:%d got message %s", clientId, msg)
		logging.Tracef("unix:%d got message %s", clientId, msg)
		if !strings.ContainsRune(msg, ':') {
			_, innererr := conn.Write([]byte("error: invalid command\n"))
			if innererr != nil {
@@ -119,7 +123,7 @@ func (as *AercServer) handleClient(conn net.Conn) {
			}
		}
	}
	logging.Debugf("unix:%d closed connection", clientId)
	logging.Tracef("unix:%d closed connection", clientId)
}

func ConnectAndExec(msg string) error {
diff --git a/lib/threadbuilder.go b/lib/threadbuilder.go
index 600f65394569..34f143a41390 100644
--- a/lib/threadbuilder.go
+++ b/lib/threadbuilder.go
@@ -67,7 +67,7 @@ func (builder *ThreadBuilder) Threads(uids []uint32, inverse bool, sort bool,
	builder.RebuildUids(threads, inverse)

	elapsed := time.Since(start)
	logging.Infof("%d threads from %d uids created in %s", len(threads),
	logging.Tracef("%d threads from %d uids created in %s", len(threads),
		len(uids), elapsed)

	return threads
diff --git a/widgets/account.go b/widgets/account.go
index 5bbe97e1dbc7..ca899c939f71 100644
--- a/widgets/account.go
+++ b/widgets/account.go
@@ -235,7 +235,7 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
		switch msg.InResponseTo().(type) {
		case *types.Connect, *types.Reconnect:
			acct.SetStatus(statusline.ConnectionActivity("Listing mailboxes..."))
			logging.Debugf("Listing mailboxes...")
			logging.Tracef("Listing mailboxes...")
			acct.dirlist.UpdateList(func(dirs []string) {
				var dir string
				for _, _dir := range dirs {
@@ -251,14 +251,14 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
					acct.dirlist.Select(dir)
				}
				acct.msglist.SetInitDone()
				logging.Infof("%s connected.", acct.acct.Name)
				logging.Infof("[%s] connected.", acct.acct.Name)
				acct.SetStatus(statusline.SetConnected(true))
				acct.newConn = true
			})
		case *types.Disconnect:
			acct.dirlist.ClearList()
			acct.msglist.SetStore(nil)
			logging.Infof("%s disconnected.", acct.acct.Name)
			logging.Infof("[%s] disconnected.", acct.acct.Name)
			acct.SetStatus(statusline.SetConnected(false))
		case *types.OpenDirectory:
			if store, ok := acct.dirlist.SelectedMsgStore(); ok {
@@ -347,13 +347,13 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
	case *types.LabelList:
		acct.labels = msg.Labels
	case *types.ConnError:
		logging.Errorf("%s connection error: %v", acct.acct.Name, msg.Error)
		logging.Errorf("[%s] connection error: %v", acct.acct.Name, msg.Error)
		acct.SetStatus(statusline.SetConnected(false))
		acct.PushError(msg.Error)
		acct.msglist.SetStore(nil)
		acct.worker.PostAction(&types.Reconnect{}, nil)
	case *types.Error:
		logging.Errorf("%s unexpected error: %v", acct.acct.Name, msg.Error)
		logging.Errorf("[%s] unexpected error: %v", acct.acct.Name, msg.Error)
		acct.PushError(msg.Error)
	}
	acct.UpdateStatus()
@@ -427,7 +427,7 @@ func (acct *AccountView) CheckMail() {
	dirs := acct.dirlist.List()
	dirs = acct.dirlist.FilterDirs(dirs, acct.AccountConfig().CheckMailInclude, false)
	dirs = acct.dirlist.FilterDirs(dirs, exclude, true)
	logging.Infof("Checking for new mail on account %s", acct.Name())
	logging.Debugf("Checking for new mail on account %s", acct.Name())
	acct.SetStatus(statusline.ConnectionActivity("Checking for new mail..."))
	msg := &types.CheckMail{
		Directories: dirs,
diff --git a/widgets/aerc.go b/widgets/aerc.go
index 163ba9e051c1..dce28c3e77f6 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -750,7 +750,7 @@ func (aerc *Aerc) Mbox(source string) error {
		acctConf = *selectedAcct.acct
		info := fmt.Sprintf("Loading outgoing mbox mail settings from account [%s]", selectedAcct.Name())
		aerc.PushStatus(info, 10*time.Second)
		logging.Infof(info)
		logging.Debugf(info)
	} else {
		acctConf.From = "<user@localhost>"
	}
diff --git a/widgets/compose.go b/widgets/compose.go
index ca7c8b8fb5fe..1bbdb477cf0b 100644
--- a/widgets/compose.go
+++ b/widgets/compose.go
@@ -109,7 +109,7 @@ func NewComposer(aerc *Aerc, acct *AccountView, conf *config.AercConfig,

func (c *Composer) SwitchAccount(newAcct *AccountView) error {
	if c.acct == newAcct {
		logging.Infof("same accounts: no switch")
		logging.Tracef("same accounts: no switch")
		return nil
	}
	// sync the header with the editors
@@ -127,7 +127,7 @@ func (c *Composer) SwitchAccount(newAcct *AccountView) error {
		editor.loadValue()
	}
	c.Invalidate()
	logging.Infof("account sucessfully switched")
	logging.Debugf("account sucessfully switched")
	return nil
}

diff --git a/widgets/dirlist.go b/widgets/dirlist.go
index 0f8431e96d37..4663d487499f 100644
--- a/widgets/dirlist.go
+++ b/widgets/dirlist.go
@@ -187,7 +187,7 @@ func (dirlist *DirectoryList) Select(name string) {
				})
			dirlist.Invalidate()
		case <-ctx.Done():
			logging.Debugf("dirlist: skip %s", name)
			logging.Tracef("dirlist: skip %s", name)
			return
		}
	}(ctx)
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index 1cc2d6f567da..019f9d6ef8d0 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -240,7 +240,7 @@ func createSwitcher(acct *AccountView, switcher *PartSwitcher,
			return err
		}
		selectedPriority := -1
		logging.Infof("Selecting best message from %v", conf.Viewer.Alternatives)
		logging.Tracef("Selecting best message from %v", conf.Viewer.Alternatives)
		for i, pv := range switcher.parts {
			// Switch to user's preferred mimetype
			if switcher.selected == -1 && pv.part.MIMEType != "multipart" {
diff --git a/worker/imap/cache.go b/worker/imap/cache.go
index c32131d38b4f..cf92dfaafffd 100644
--- a/worker/imap/cache.go
+++ b/worker/imap/cache.go
@@ -45,9 +45,9 @@ func (w *IMAPWorker) initCacheDb(acct string) {
		return
	}
	w.cache = db
	logging.Infof("cache db opened: %s", p)
	logging.Debugf("cache db opened: %s", p)
	if w.config.cacheMaxAge.Hours() > 0 {
		go w.cleanCache()
		go w.cleanCache(p)
	}
}

@@ -84,7 +84,7 @@ func (w *IMAPWorker) cacheHeader(mi *models.MessageInfo) {
}

func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
	logging.Debugf("Retrieving headers from cache: %v", msg.Uids)
	logging.Tracef("Retrieving headers from cache: %v", msg.Uids)
	var need []uint32
	uv := fmt.Sprintf("%d", w.selected.UidValidity)
	for _, uid := range msg.Uids {
@@ -122,7 +122,7 @@ func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
		if err != nil {
			mi.Refs = refs
		}
		logging.Debugf("located cached header %s.%s", uv, u)
		logging.Tracef("located cached header %s.%s", uv, u)
		w.worker.PostMessage(&types.MessageInfo{
			Message:    types.RespondTo(msg),
			Info:       mi,
@@ -144,7 +144,7 @@ func cacheDir() (string, error) {
}

// cleanCache removes stale entries from the selected mailbox cachedb
func (w *IMAPWorker) cleanCache() {
func (w *IMAPWorker) cleanCache(path string) {
	start := time.Now()
	var scanned, removed int
	iter := w.cache.NewIterator(nil, nil)
@@ -170,5 +170,6 @@ func (w *IMAPWorker) cleanCache() {
	}
	iter.Release()
	elapsed := time.Since(start)
	logging.Infof("cleaned cache, removed %d of %d entries in %s", removed, scanned, elapsed)
	logging.Debugf("%s: removed %d/%d expired entries in %s",
		path, removed, scanned, elapsed)
}
diff --git a/worker/imap/checkmail.go b/worker/imap/checkmail.go
index e0aef71b4fd0..0f347e099f49 100644
--- a/worker/imap/checkmail.go
+++ b/worker/imap/checkmail.go
@@ -20,7 +20,7 @@ func (w *IMAPWorker) handleCheckMailMessage(msg *types.CheckMail) {
			continue
		}

		logging.Debugf("Getting status of directory %s", dir)
		logging.Tracef("Getting status of directory %s", dir)
		status, err := w.client.Status(dir, items)
		if err != nil {
			w.worker.PostMessage(&types.Error{
diff --git a/worker/imap/fetch.go b/worker/imap/fetch.go
index f540708726b8..9256c6ebdb9b 100644
--- a/worker/imap/fetch.go
+++ b/worker/imap/fetch.go
@@ -27,7 +27,7 @@ func (imapw *IMAPWorker) handleFetchMessageHeaders(
			nil)
		return
	}
	logging.Infof("Fetching message headers: %v", toFetch)
	logging.Tracef("Fetching message headers: %v", toFetch)
	section := &imap.BodySectionName{
		BodyPartName: imap.BodyPartName{
			Specifier: imap.HeaderSpecifier,
@@ -84,7 +84,7 @@ func (imapw *IMAPWorker) handleFetchMessageHeaders(
func (imapw *IMAPWorker) handleFetchMessageBodyPart(
	msg *types.FetchMessageBodyPart,
) {
	logging.Infof("Fetching message %d part: %v", msg.Uid, msg.Part)
	logging.Tracef("Fetching message %d part: %v", msg.Uid, msg.Part)

	var partHeaderSection imap.BodySectionName
	partHeaderSection.Peek = true
@@ -158,7 +158,7 @@ func (imapw *IMAPWorker) handleFetchMessageBodyPart(
func (imapw *IMAPWorker) handleFetchFullMessages(
	msg *types.FetchFullMessages,
) {
	logging.Infof("Fetching full messages: %v", msg.Uids)
	logging.Tracef("Fetching full messages: %v", msg.Uids)
	section := &imap.BodySectionName{
		Peek: true,
	}
diff --git a/worker/imap/idler.go b/worker/imap/idler.go
index 65ba6b9b22d2..da018334f2c8 100644
--- a/worker/imap/idler.go
+++ b/worker/imap/idler.go
@@ -166,5 +166,5 @@ func (i *idler) waitOnIdle() {

func (i *idler) log(format string, v ...interface{}) {
	msg := fmt.Sprintf(format, v...)
	logging.Debugf("idler (%p) [idle:%t,wait:%t] %s", i, i.isIdleing(), i.isWaiting(), msg)
	logging.Tracef("idler (%p) [idle:%t,wait:%t] %s", i, i.isIdleing(), i.isWaiting(), msg)
}
diff --git a/worker/imap/list.go b/worker/imap/list.go
index 67d4c33d2579..c3211f2138c5 100644
--- a/worker/imap/list.go
+++ b/worker/imap/list.go
@@ -10,7 +10,7 @@ import (

func (imapw *IMAPWorker) handleListDirectories(msg *types.ListDirectories) {
	mailboxes := make(chan *imap.MailboxInfo)
	logging.Infof("Listing mailboxes")
	logging.Tracef("Listing mailboxes")
	done := make(chan interface{})

	go func() {
@@ -62,7 +62,7 @@ func (imapw *IMAPWorker) handleSearchDirectory(msg *types.SearchDirectory) {
		}, nil)
	}

	logging.Infof("Executing search")
	logging.Tracef("Executing search")
	criteria, err := parseSearch(msg.Argv)
	if err != nil {
		emitError(err)
diff --git a/worker/imap/observer.go b/worker/imap/observer.go
index 866fac62eff1..867b57d9aa3a 100644
--- a/worker/imap/observer.go
+++ b/worker/imap/observer.go
@@ -150,5 +150,5 @@ func (o *observer) emit(errMsg string) {

func (o *observer) log(format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	logging.Debugf("observer (%p) [running:%t] %s", o, o.running, msg)
	logging.Tracef("observer (%p) [running:%t] %s", o, o.running, msg)
}
diff --git a/worker/imap/open.go b/worker/imap/open.go
index f3f20a590640..f554d5247fa8 100644
--- a/worker/imap/open.go
+++ b/worker/imap/open.go
@@ -10,7 +10,7 @@ import (
)

func (imapw *IMAPWorker) handleOpenDirectory(msg *types.OpenDirectory) {
	logging.Infof("Opening %s", msg.Directory)
	logging.Debugf("Opening %s", msg.Directory)

	sel, err := imapw.client.Select(msg.Directory, false)
	if err != nil {
@@ -27,7 +27,7 @@ func (imapw *IMAPWorker) handleOpenDirectory(msg *types.OpenDirectory) {
func (imapw *IMAPWorker) handleFetchDirectoryContents(
	msg *types.FetchDirectoryContents,
) {
	logging.Infof("Fetching UID list")
	logging.Tracef("Fetching UID list")

	searchCriteria, err := parseSearch(msg.FilterCriteria)
	if err != nil {
@@ -64,7 +64,7 @@ func (imapw *IMAPWorker) handleFetchDirectoryContents(
			Error:   err,
		}, nil)
	} else {
		logging.Infof("Found %d UIDs", len(uids))
		logging.Tracef("Found %d UIDs", len(uids))
		if len(msg.FilterCriteria) == 1 {
			// Only initialize if we are not filtering
			imapw.seqMap.Initialize(uids)
@@ -105,7 +105,7 @@ func translateSortCriterions(
func (imapw *IMAPWorker) handleDirectoryThreaded(
	msg *types.FetchDirectoryThreaded,
) {
	logging.Infof("Fetching threaded UID list")
	logging.Tracef("Fetching threaded UID list")

	searchCriteria, err := parseSearch(msg.FilterCriteria)
	if err != nil {
@@ -125,7 +125,7 @@ func (imapw *IMAPWorker) handleDirectoryThreaded(
	} else {
		aercThreads, count := convertThreads(threads, nil)
		sort.Sort(types.ByUID(aercThreads))
		logging.Infof("Found %d threaded messages", count)
		logging.Tracef("Found %d threaded messages", count)
		if len(msg.FilterCriteria) == 1 {
			// Only initialize if we are not filtering
			var uids []uint32
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index 506eb182ed9a..c3021f91caf2 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -93,14 +93,14 @@ func (w *IMAPWorker) newClient(c *client.Client) {
	sort, err := w.client.sort.SupportSort()
	if err == nil && sort {
		w.caps.Sort = true
		logging.Infof("Server Capability found: Sort")
		logging.Debugf("Server Capability found: Sort")
	}
	for _, alg := range []sortthread.ThreadAlgorithm{sortthread.References, sortthread.OrderedSubject} {
		ok, err := w.client.Support(fmt.Sprintf("THREAD=%s", string(alg)))
		if err == nil && ok {
			w.threadAlgorithm = alg
			w.caps.Thread = true
			logging.Infof("Server Capability found: Thread (algorithm: %s)", string(alg))
			logging.Debugf("Server Capability found: Thread (algorithm: %s)", string(alg))
			break
		}
	}
@@ -233,7 +233,7 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
}

func (w *IMAPWorker) handleImapUpdate(update client.Update) {
	logging.Debugf("(= %T", update)
	logging.Tracef("(= %T", update)
	switch update := update.(type) {
	case *client.MailboxUpdate:
		status := update.Mailbox
diff --git a/worker/maildir/search.go b/worker/maildir/search.go
index 729d521f6e11..0f3f6a429787 100644
--- a/worker/maildir/search.go
+++ b/worker/maildir/search.go
@@ -91,7 +91,7 @@ func getParsedFlag(name string) maildir.Flag {

func (w *Worker) search(criteria *searchCriteria) ([]uint32, error) {
	requiredParts := getRequiredParts(criteria)
	logging.Infof("Required parts bitmask for search: %b", requiredParts)
	logging.Debugf("Required parts bitmask for search: %b", requiredParts)

	keys, err := w.c.UIDs(*w.selected)
	if err != nil {
diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go
index 2cf7897a07fb..2a8a49bd5ce4 100644
--- a/worker/maildir/worker.go
+++ b/worker/maildir/worker.go
@@ -200,7 +200,7 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
			keyFlags[key] = flags
		}
	} else {
		logging.Infof("disabled flags cache: %q: %v", dir, err)
		logging.Tracef("disabled flags cache: %q: %v", dir, err)
	}

	uids, err := w.c.UIDs(dir)
@@ -221,7 +221,8 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
			ok := false
			flags, ok = keyFlags[message.key]
			if !ok {
				logging.Debugf("message (key=%q uid=%d) not found in map cache", message.key, message.uid)
				logging.Tracef("message (key=%q uid=%d) not found in map cache",
					message.key, message.uid)
				flags, err = message.Flags()
				if err != nil {
					logging.Errorf("could not get flags: %v", err)
@@ -320,7 +321,7 @@ func (w *Worker) handleConfigure(msg *types.Configure) error {
		return err
	}
	w.c = c
	logging.Infof("configured base maildir: %s", dir)
	logging.Debugf("configured base maildir: %s", dir)
	return nil
}

@@ -357,7 +358,7 @@ func (w *Worker) handleListDirectories(msg *types.ListDirectories) error {
}

func (w *Worker) handleOpenDirectory(msg *types.OpenDirectory) error {
	logging.Infof("opening %s", msg.Directory)
	logging.Debugf("opening %s", msg.Directory)

	// open the directory
	dir, err := w.c.OpenDirectory(msg.Directory)
@@ -767,13 +768,13 @@ func (w *Worker) handleAppendMessage(msg *types.AppendMessage) error {
	dest := w.c.Store.Dir(msg.Destination)
	_, writer, err := dest.Create(lib.ToMaildirFlags(msg.Flags))
	if err != nil {
		logging.Errorf("could not create message at %s: %v", msg.Destination, err)
		return err
		return fmt.Errorf("could not create message at %s: %w",
			msg.Destination, err)
	}
	defer writer.Close()
	if _, err := io.Copy(writer, msg.Reader); err != nil {
		logging.Errorf("could not write message to destination: %v", err)
		return err
		return fmt.Errorf(
			"could not write message to destination: %w", err)
	}
	w.worker.PostMessage(&types.Done{
		Message: types.RespondTo(msg),
@@ -785,12 +786,12 @@ func (w *Worker) handleAppendMessage(msg *types.AppendMessage) error {
}

func (w *Worker) handleSearchDirectory(msg *types.SearchDirectory) error {
	logging.Infof("Searching directory %v with args: %v", *w.selected, msg.Argv)
	logging.Debugf("Searching directory %v with args: %v", *w.selected, msg.Argv)
	criteria, err := parseSearch(msg.Argv)
	if err != nil {
		return err
	}
	logging.Infof("Searching with parsed criteria: %#v", criteria)
	logging.Tracef("Searching with parsed criteria: %#v", criteria)
	uids, err := w.search(criteria)
	if err != nil {
		return err
diff --git a/worker/mbox/worker.go b/worker/mbox/worker.go
index a786a65eb0fb..19a4497f4cd8 100644
--- a/worker/mbox/worker.go
+++ b/worker/mbox/worker.go
@@ -69,7 +69,7 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
			reterr = err
			break
		} else {
			logging.Infof("configured with mbox file %s", dir)
			logging.Debugf("configured with mbox file %s", dir)
		}

	case *types.Connect, *types.Reconnect, *types.Disconnect:
@@ -106,7 +106,7 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
			Info: w.data.DirectoryInfo(msg.Directory),
		}, nil)
		w.worker.PostMessage(&types.Done{Message: types.RespondTo(msg)}, nil)
		logging.Infof("%s opened", msg.Directory)
		logging.Debugf("%s opened", msg.Directory)

	case *types.FetchDirectoryContents:
		uids, err := filterUids(w.folder, w.folder.Uids(), msg.FilterCriteria)
@@ -377,7 +377,7 @@ func filterUids(folder *container, uids []uint32, args []string) ([]uint32, erro
	if err != nil {
		return nil, err
	}
	logging.Infof("Search with parsed criteria: %#v", criteria)
	logging.Debugf("Search with parsed criteria: %#v", criteria)
	m := make([]lib.RawMessage, 0, len(uids))
	for _, uid := range uids {
		msg, err := folder.Message(uid)
diff --git a/worker/notmuch/worker.go b/worker/notmuch/worker.go
index 0acd4e786806..5f5e403c7abe 100644
--- a/worker/notmuch/worker.go
+++ b/worker/notmuch/worker.go
@@ -275,7 +275,7 @@ func (w *worker) getDirectoryInfo(name string, query string) *models.DirectoryIn
}

func (w *worker) handleOpenDirectory(msg *types.OpenDirectory) error {
	logging.Infof("opening %s", msg.Directory)
	logging.Tracef("opening %s", msg.Directory)

	var isDynamicFolder bool
	q := ""
diff --git a/worker/types/worker.go b/worker/types/worker.go
index d21a46a5c33a..67cb98744295 100644
--- a/worker/types/worker.go
+++ b/worker/types/worker.go
@@ -84,9 +84,9 @@ func (worker *Worker) PostAction(msg WorkerMessage, cb func(msg WorkerMessage))
	worker.setId(msg)

	if resp := msg.InResponseTo(); resp != nil {
		logging.Debugf("PostAction %T:%T", msg, resp)
		logging.Tracef("PostAction %T:%T", msg, resp)
	} else {
		logging.Debugf("PostAction %T", msg)
		logging.Tracef("PostAction %T", msg)
	}
	// write to Actions channel without blocking
	worker.queue(msg)
@@ -107,9 +107,9 @@ func (worker *Worker) PostMessage(msg WorkerMessage,
	msg.setAccount(worker.Name)

	if resp := msg.InResponseTo(); resp != nil {
		logging.Debugf("PostMessage %T:%T", msg, resp)
		logging.Tracef("PostMessage %T:%T", msg, resp)
	} else {
		logging.Debugf("PostMessage %T", msg)
		logging.Tracef("PostMessage %T", msg)
	}
	ui.MsgChannel <- msg

@@ -122,9 +122,9 @@ func (worker *Worker) PostMessage(msg WorkerMessage,

func (worker *Worker) ProcessMessage(msg WorkerMessage) WorkerMessage {
	if resp := msg.InResponseTo(); resp != nil {
		logging.Debugf("ProcessMessage %T(%d):%T(%d)", msg, msg.getId(), resp, resp.getId())
		logging.Tracef("ProcessMessage %T(%d):%T(%d)", msg, msg.getId(), resp, resp.getId())
	} else {
		logging.Debugf("ProcessMessage %T(%d)", msg, msg.getId())
		logging.Tracef("ProcessMessage %T(%d)", msg, msg.getId())
	}
	if inResponseTo := msg.InResponseTo(); inResponseTo != nil {
		worker.Lock()
@@ -144,9 +144,9 @@ func (worker *Worker) ProcessMessage(msg WorkerMessage) WorkerMessage {

func (worker *Worker) ProcessAction(msg WorkerMessage) WorkerMessage {
	if resp := msg.InResponseTo(); resp != nil {
		logging.Debugf("ProcessAction %T(%d):%T(%d)", msg, msg.getId(), resp, resp.getId())
		logging.Tracef("ProcessAction %T(%d):%T(%d)", msg, msg.getId(), resp, resp.getId())
	} else {
		logging.Debugf("ProcessAction %T(%d)", msg, msg.getId())
		logging.Tracef("ProcessAction %T(%d)", msg, msg.getId())
	}
	if inResponseTo := msg.InResponseTo(); inResponseTo != nil {
		worker.Lock()
-- 
2.38.1

[PATCH aerc v2 5/5] logging: rename package to log

Details
Message ID
<20221127123203.145179-6-robin@jarry.cc>
In-Reply-To
<20221127123203.145179-1-robin@jarry.cc> (view parent)
DKIM signature
pass
Download raw message
Patch: +409 -413
Use the same name than the builtin "log" package. That way, we do not
risk logging in the wrong place.

Suggested-by: Tim Culverhouse <tim@timculverhouse.com>
Signed-off-by: Robin Jarry <robin@jarry.cc>
---
 .gitignore                       |  1 -
 CONTRIBUTING.md                  | 12 ++---
 README.md                        |  2 +-
 aerc.go                          | 28 ++++++------
 commands/account/compose.go      |  4 +-
 commands/account/export-mbox.go  | 16 +++----
 commands/account/import-mbox.go  | 16 +++----
 commands/account/recover.go      |  4 +-
 commands/account/search.go       |  6 +--
 commands/compose/attach.go       | 23 +++++-----
 commands/compose/postpone.go     |  8 ++--
 commands/compose/send.go         |  8 ++--
 commands/exec.go                 |  4 +-
 commands/history.go              |  4 +-
 commands/msg/archive.go          |  4 +-
 commands/msg/envelope.go         |  4 +-
 commands/msg/forward.go          | 14 +++---
 commands/msg/invite.go           |  4 +-
 commands/msg/pipe.go             | 10 ++---
 commands/msg/recall.go           | 10 ++---
 commands/msg/reply.go            | 10 ++---
 commands/msg/unsubscribe.go      |  6 +--
 commands/msgview/save.go         |  4 +-
 commands/util.go                 |  4 +-
 completer/completer.go           | 10 ++---
 config/accounts.go               |  6 +--
 config/binds.go                  |  8 ++--
 config/compose.go                |  4 +-
 config/filters.go                |  4 +-
 config/general.go                | 22 ++++-----
 config/openers.go                |  4 +-
 config/statusline.go             |  4 +-
 config/templates.go              |  4 +-
 config/triggers.go               |  6 +--
 config/ui.go                     |  6 +--
 config/viewer.go                 |  4 +-
 doc/aerc.1.scd                   |  2 +-
 lib/attachment.go                |  4 +-
 lib/crypto/gpg/gpgbin/gpgbin.go  |  8 ++--
 lib/crypto/pgp/pgp.go            |  4 +-
 lib/messageview.go               |  6 +--
 lib/msgstore.go                  |  6 +--
 lib/open.go                      |  6 +--
 lib/parse/ansi.go                |  6 +--
 lib/socket.go                    | 30 ++++++-------
 lib/threadbuilder.go             |  6 +--
 lib/ui/textinput.go              |  4 +-
 {logging => log}/logger.go       |  2 +-
 {logging => log}/panic-logger.go |  2 +-
 widgets/account.go               | 18 ++++----
 widgets/aerc.go                  | 10 ++---
 widgets/compose.go               | 30 ++++++-------
 widgets/dirlist.go               |  6 +--
 widgets/dirtree.go               |  6 +--
 widgets/listbox.go               |  4 +-
 widgets/msglist.go               |  4 +-
 widgets/msgviewer.go             | 22 ++++-----
 widgets/spinner.go               |  4 +-
 widgets/status.go                |  4 +-
 widgets/terminal.go              |  4 +-
 worker/imap/cache.go             | 30 ++++++-------
 worker/imap/checkmail.go         |  4 +-
 worker/imap/connect.go           |  8 ++--
 worker/imap/fetch.go             | 12 ++---
 worker/imap/flags.go             |  4 +-
 worker/imap/idler.go             |  8 ++--
 worker/imap/list.go              |  8 ++--
 worker/imap/observer.go          |  4 +-
 worker/imap/open.go              | 16 +++----
 worker/imap/worker.go            | 12 ++---
 worker/lib/parse.go              |  4 +-
 worker/maildir/search.go         |  6 +--
 worker/maildir/worker.go         | 76 ++++++++++++++++----------------
 worker/mbox/worker.go            | 30 ++++++-------
 worker/notmuch/eventhandlers.go  |  4 +-
 worker/notmuch/lib/database.go   | 16 +++----
 worker/notmuch/worker.go         | 72 +++++++++++++++---------------
 worker/types/thread.go           |  4 +-
 worker/types/worker.go           | 18 ++++----
 79 files changed, 409 insertions(+), 413 deletions(-)
 rename {logging => log}/logger.go (99%)
 rename {logging => log}/panic-logger.go (98%)

diff --git a/.gitignore b/.gitignore
index a50cf870fdf2..7caf227cce74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@
/aerc
/aerc.debug
/.aerc.d
log
race.log.*
raw.log
*.1
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 03c606ac7640..44a567be44a3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -243,19 +243,19 @@ If gofumpt accepts your code it's most likely properly formatted.
### Logging

Aerc allows logging messages to a file. Either by redirecting the output to
a file (e.g. `aerc > log`), or by configuring `log-file` in ``aerc.conf`.
a file (e.g. `aerc > aerc.log`), or by configuring `log-file` in ``aerc.conf`.
Logging messages are associated with a severity level, from lowest to highest:
`trace`, `debug`, `info`, `warn`, `error`.

Messages can be sent to the log file by using the following functions:

- `logging.Errorf()`: Use to report serious (but non-fatal) errors.
- `logging.Warnf()`: Use to report issues that do not affect normal use.
- `logging.Infof()`: Use to display important messages that may concern
- `log.Errorf()`: Use to report serious (but non-fatal) errors.
- `log.Warnf()`: Use to report issues that do not affect normal use.
- `log.Infof()`: Use to display important messages that may concern
  non-developers.
- `logging.Debugf()`: Use to display non-important messages, or debuging
- `log.Debugf()`: Use to display non-important messages, or debuging
  details.
- `logging.Tracef()`: Use to display only low level debugging traces.
- `log.Tracef()`: Use to display only low level debugging traces.

### Man pages

diff --git a/README.md b/README.md
index d8a84fcc3985..37857d0e76ec 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ and show the account configuration wizard.

If you redirect stdout to a file, logging output will be written to that file:

    $ aerc > log
    $ aerc > aerc.log

Note that the example HTML filter (off by default), additionally needs `w3m` and
`dante` to be installed.
diff --git a/aerc.go b/aerc.go
index b74697680043..dcd34170ceee 100644
--- a/aerc.go
+++ b/aerc.go
@@ -26,7 +26,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib/crypto"
	"git.sr.ht/~rjarry/aerc/lib/templates"
	libui "git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -113,19 +113,19 @@ func usage(msg string) {
}

func setWindowTitle() {
	logging.Tracef("Parsing terminfo")
	log.Tracef("Parsing terminfo")
	ti, err := terminfo.LoadFromEnv()
	if err != nil {
		logging.Warnf("Cannot get terminfo: %v", err)
		log.Warnf("Cannot get terminfo: %v", err)
		return
	}

	if !ti.Has(terminfo.HasStatusLine) {
		logging.Infof("Terminal does not have status line support")
		log.Infof("Terminal does not have status line support")
		return
	}

	logging.Debugf("Setting terminal title")
	log.Debugf("Setting terminal title")
	buf := new(bytes.Buffer)
	ti.Fprintf(buf, terminfo.ToStatusLine)
	fmt.Fprint(buf, "aerc")
@@ -134,17 +134,17 @@ func setWindowTitle() {
}

func main() {
	defer logging.PanicHandler()
	defer log.PanicHandler()
	opts, optind, err := getopt.Getopts(os.Args, "va:")
	if err != nil {
		usage("error: " + err.Error())
		return
	}
	logging.BuildInfo = buildInfo()
	log.BuildInfo = buildInfo()
	var accts []string
	for _, opt := range opts {
		if opt.Option == 'v' {
			fmt.Println("aerc " + logging.BuildInfo)
			fmt.Println("aerc " + log.BuildInfo)
			return
		}
		if opt.Option == 'a' {
@@ -173,7 +173,7 @@ func main() {
		os.Exit(1) //nolint:gocritic // PanicHandler does not need to run as it's not a panic
	}

	logging.Infof("Starting up version %s", logging.BuildInfo)
	log.Infof("Starting up version %s", log.BuildInfo)

	var (
		aerc *widgets.Aerc
@@ -185,7 +185,7 @@ func main() {
	c := crypto.New(conf.General.PgpProvider)
	err = c.Init()
	if err != nil {
		logging.Warnf("failed to initialise crypto interface: %v", err)
		log.Warnf("failed to initialise crypto interface: %v", err)
	}
	defer c.Close()

@@ -200,7 +200,7 @@ func main() {
		panic(err)
	}
	defer ui.Close()
	logging.UICleanup = func() {
	log.UICleanup = func() {
		ui.Close()
	}
	close(deferLoop)
@@ -211,7 +211,7 @@ func main() {

	as, err := lib.StartServer()
	if err != nil {
		logging.Warnf("Failed to start Unix server: %v", err)
		log.Warnf("Failed to start Unix server: %v", err)
	} else {
		defer as.Close()
		as.OnMailto = aerc.Mailto
@@ -229,7 +229,7 @@ func main() {
			fmt.Fprintf(os.Stderr, "Failed to communicate to aerc: %v\n", err)
			err = aerc.CloseBackends()
			if err != nil {
				logging.Warnf("failed to close backends: %v", err)
				log.Warnf("failed to close backends: %v", err)
			}
			return
		}
@@ -256,6 +256,6 @@ func main() {
	}
	err = aerc.CloseBackends()
	if err != nil {
		logging.Warnf("failed to close backends: %v", err)
		log.Warnf("failed to close backends: %v", err)
	}
}
diff --git a/commands/account/compose.go b/commands/account/compose.go
index 16474b4c8995..3d3d9afbe61b 100644
--- a/commands/account/compose.go
+++ b/commands/account/compose.go
@@ -11,7 +11,7 @@ import (
	"github.com/emersion/go-message/mail"

	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~sircmpwn/getopt"
@@ -68,7 +68,7 @@ func (Compose) Execute(aerc *widgets.Aerc, args []string) error {
		ui.Invalidate()
	})
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		composer.AppendContents(msg.Body)
	}()
diff --git a/commands/account/export-mbox.go b/commands/account/export-mbox.go
index f51608b904ad..cbb56e61c22c 100644
--- a/commands/account/export-mbox.go
+++ b/commands/account/export-mbox.go
@@ -8,7 +8,7 @@ import (
	"sync"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/widgets"
	mboxer "git.sr.ht/~rjarry/aerc/worker/mbox"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -55,7 +55,7 @@ func (ExportMbox) Execute(aerc *widgets.Aerc, args []string) error {
	go func() {
		file, err := os.Create(filename)
		if err != nil {
			logging.Errorf("failed to create file: %v", err)
			log.Errorf("failed to create file: %v", err)
			aerc.PushError(err.Error())
			return
		}
@@ -74,16 +74,16 @@ func (ExportMbox) Execute(aerc *widgets.Aerc, args []string) error {
			if retries > 0 {
				if retries > 10 {
					errorMsg := fmt.Sprintf("too many retries: %d; stopping export", retries)
					logging.Errorf(errorMsg)
					log.Errorf(errorMsg)
					aerc.PushError(args[0] + " " + errorMsg)
					break
				}
				sleeping := time.Duration(retries * 1e9 * 2)
				logging.Debugf("sleeping for %s before retrying; retries: %d", sleeping, retries)
				log.Debugf("sleeping for %s before retrying; retries: %d", sleeping, retries)
				time.Sleep(sleeping)
			}

			logging.Debugf("fetching %d for export", len(uids))
			log.Debugf("fetching %d for export", len(uids))
			acct.Worker().PostAction(&types.FetchFullMessages{
				Uids: uids,
			}, func(msg types.WorkerMessage) {
@@ -91,14 +91,14 @@ func (ExportMbox) Execute(aerc *widgets.Aerc, args []string) error {
				case *types.Done:
					done <- true
				case *types.Error:
					logging.Errorf("failed to fetch message: %v", msg.Error)
					log.Errorf("failed to fetch message: %v", msg.Error)
					aerc.PushError(args[0] + " error encountered: " + msg.Error.Error())
					done <- false
				case *types.FullMessage:
					mu.Lock()
					err := mboxer.Write(file, msg.Content.Reader, "", t)
					if err != nil {
						logging.Warnf("failed to write mbox: %v", err)
						log.Warnf("failed to write mbox: %v", err)
					}
					for i, uid := range uids {
						if uid == msg.Content.Uid {
@@ -117,7 +117,7 @@ func (ExportMbox) Execute(aerc *widgets.Aerc, args []string) error {
		}
		statusInfo := fmt.Sprintf("Exported %d of %d messages to %s.", ctr, len(store.Uids()), filename)
		aerc.PushStatus(statusInfo, 10*time.Second)
		logging.Debugf(statusInfo)
		log.Debugf(statusInfo)
	}()

	return nil
diff --git a/commands/account/import-mbox.go b/commands/account/import-mbox.go
index 93408acadb4b..7dab19588ca7 100644
--- a/commands/account/import-mbox.go
+++ b/commands/account/import-mbox.go
@@ -11,7 +11,7 @@ import (
	"time"

	"git.sr.ht/~rjarry/aerc/commands"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	mboxer "git.sr.ht/~rjarry/aerc/worker/mbox"
@@ -55,7 +55,7 @@ func (ImportMbox) Execute(aerc *widgets.Aerc, args []string) error {
	importFolder := func() {
		statusInfo := fmt.Sprintln("Importing", filename, "to folder", folder)
		aerc.PushStatus(statusInfo, 10*time.Second)
		logging.Debugf(statusInfo)
		log.Debugf(statusInfo)
		f, err := os.Open(filename)
		if err != nil {
			aerc.PushError(err.Error())
@@ -78,7 +78,7 @@ func (ImportMbox) Execute(aerc *widgets.Aerc, args []string) error {
				var buf bytes.Buffer
				r, err := m.NewReader()
				if err != nil {
					logging.Errorf("could not get reader for uid %d", m.UID())
					log.Errorf("could not get reader for uid %d", m.UID())
					break
				}
				nbytes, _ := io.Copy(&buf, r)
@@ -92,11 +92,11 @@ func (ImportMbox) Execute(aerc *widgets.Aerc, args []string) error {
					switch msg := msg.(type) {
					case *types.Unsupported:
						errMsg := fmt.Sprintf("%s: AppendMessage is unsupported", args[0])
						logging.Errorf(errMsg)
						log.Errorf(errMsg)
						aerc.PushError(errMsg)
						return
					case *types.Error:
						logging.Errorf("AppendMessage failed: %v", msg.Error)
						log.Errorf("AppendMessage failed: %v", msg.Error)
						done <- false
					case *types.Done:
						atomic.AddUint32(&appended, 1)
@@ -113,17 +113,17 @@ func (ImportMbox) Execute(aerc *widgets.Aerc, args []string) error {
						retries -= 1
						sleeping := time.Duration((5 - retries) * 1e9)

						logging.Debugf("sleeping for %s before append message %d again", sleeping, i)
						log.Debugf("sleeping for %s before append message %d again", sleeping, i)
						time.Sleep(sleeping)
					}
				case <-time.After(30 * time.Second):
					logging.Warnf("timed-out; appended %d of %d", appended, len(messages))
					log.Warnf("timed-out; appended %d of %d", appended, len(messages))
					return
				}
			}
		}
		infoStr := fmt.Sprintf("%s: imported %d of %d sucessfully.", args[0], appended, len(messages))
		logging.Debugf(infoStr)
		log.Debugf(infoStr)
		aerc.SetStatus(infoStr)
	}

diff --git a/commands/account/recover.go b/commands/account/recover.go
index b8acd2614862..9bb73316975e 100644
--- a/commands/account/recover.go
+++ b/commands/account/recover.go
@@ -9,7 +9,7 @@ import (

	"git.sr.ht/~rjarry/aerc/commands"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~sircmpwn/getopt"
@@ -114,7 +114,7 @@ func (Recover) Execute(aerc *widgets.Aerc, args []string) error {
		ui.Invalidate()
	})
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		composer.AppendContents(bytes.NewReader(data))
	}()
diff --git a/commands/account/search.go b/commands/account/search.go
index 125cb5d7558b..1494f7886a8d 100644
--- a/commands/account/search.go
+++ b/commands/account/search.go
@@ -6,7 +6,7 @@ import (

	"git.sr.ht/~rjarry/aerc/lib/statusline"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -44,7 +44,7 @@ func (SearchFilter) Execute(aerc *widgets.Aerc, args []string) error {
		cb := func(msg types.WorkerMessage) {
			if _, ok := msg.(*types.Done); ok {
				acct.SetStatus(statusline.FilterResult(strings.Join(args, " ")))
				logging.Tracef("Filter results: %v", store.Uids())
				log.Tracef("Filter results: %v", store.Uids())
			}
		}
		store.Sort(store.GetCurrentSortCriteria(), cb)
@@ -52,7 +52,7 @@ func (SearchFilter) Execute(aerc *widgets.Aerc, args []string) error {
		acct.SetStatus(statusline.Search("Searching..."))
		cb := func(uids []uint32) {
			acct.SetStatus(statusline.Search(strings.Join(args, " ")))
			logging.Tracef("Search results: %v", uids)
			log.Tracef("Search results: %v", uids)
			store.ApplySearch(uids)
			// TODO: Remove when stores have multiple OnUpdate handlers
			ui.Invalidate()
diff --git a/commands/compose/attach.go b/commands/compose/attach.go
index de83ef0b1d78..62ae0291079c 100644
--- a/commands/compose/attach.go
+++ b/commands/compose/attach.go
@@ -12,7 +12,7 @@ import (

	"git.sr.ht/~rjarry/aerc/commands"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/widgets"
	"github.com/mitchellh/go-homedir"
)
@@ -47,24 +47,24 @@ func (a Attach) Execute(aerc *widgets.Aerc, args []string) error {
func (a Attach) addPath(aerc *widgets.Aerc, path string) error {
	path, err := homedir.Expand(path)
	if err != nil {
		logging.Errorf("failed to expand path '%s': %v", path, err)
		log.Errorf("failed to expand path '%s': %v", path, err)
		aerc.PushError(err.Error())
		return err
	}

	attachments, err := filepath.Glob(path)
	if err != nil && errors.Is(err, filepath.ErrBadPattern) {
		logging.Warnf("failed to parse as globbing pattern: %v", err)
		log.Warnf("failed to parse as globbing pattern: %v", err)
		attachments = []string{path}
	}

	composer, _ := aerc.SelectedTabContent().(*widgets.Composer)
	for _, attach := range attachments {
		logging.Debugf("attaching '%s'", attach)
		log.Debugf("attaching '%s'", attach)

		pathinfo, err := os.Stat(attach)
		if err != nil {
			logging.Errorf("failed to stat file: %v", err)
			log.Errorf("failed to stat file: %v", err)
			aerc.PushError(err.Error())
			return err
		} else if pathinfo.IsDir() && len(attachments) == 1 {
@@ -113,23 +113,23 @@ func (a Attach) openMenu(aerc *widgets.Aerc, args []string) error {
	t.OnClose = func(err error) {
		defer func() {
			if err := picks.Close(); err != nil {
				logging.Errorf("error closing file: %v", err)
				log.Errorf("error closing file: %v", err)
			}
			if err := os.Remove(picks.Name()); err != nil {
				logging.Errorf("could not remove tmp file: %v", err)
				log.Errorf("could not remove tmp file: %v", err)
			}
		}()

		aerc.CloseDialog()

		if err != nil {
			logging.Errorf("terminal closed with error: %v", err)
			log.Errorf("terminal closed with error: %v", err)
			return
		}

		_, err = picks.Seek(0, io.SeekStart)
		if err != nil {
			logging.Errorf("seek failed: %v", err)
			log.Errorf("seek failed: %v", err)
			return
		}

@@ -139,11 +139,10 @@ func (a Attach) openMenu(aerc *widgets.Aerc, args []string) error {
			if _, err := os.Stat(f); err != nil {
				continue
			}
			logging.Tracef("File picker attaches: %v", f)
			log.Tracef("File picker attaches: %v", f)
			err := a.addPath(aerc, f)
			if err != nil {
				logging.Errorf(
					"attach failed for file %s: %v", f, err)
				log.Errorf("attach failed for file %s: %v", f, err)
			}

		}
diff --git a/commands/compose/postpone.go b/commands/compose/postpone.go
index 2572d8d5a479..eb7bc0a314e0 100644
--- a/commands/compose/postpone.go
+++ b/commands/compose/postpone.go
@@ -7,7 +7,7 @@ import (
	"github.com/miolini/datacounter"
	"github.com/pkg/errors"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -47,7 +47,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {
		return errors.New("No Postpone location configured")
	}

	logging.Tracef("Postponing mail")
	log.Tracef("Postponing mail")

	header, err := composer.PrepareHeader()
	if err != nil {
@@ -70,7 +70,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {
	// run this as a goroutine so we can make other progress. The message
	// will be saved once the directory is created.
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		errStr := <-errChan
		if errStr != "" {
@@ -80,7 +80,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {

		handleErr := func(err error) {
			aerc.PushError(err.Error())
			logging.Errorf("Postponing failed: %v", err)
			log.Errorf("Postponing failed: %v", err)
			aerc.NewTab(composer, tabName)
		}

diff --git a/commands/compose/send.go b/commands/compose/send.go
index ccfe78867e19..6d9bfe253e02 100644
--- a/commands/compose/send.go
+++ b/commands/compose/send.go
@@ -17,7 +17,7 @@ import (

	"git.sr.ht/~rjarry/aerc/commands/mode"
	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -104,7 +104,7 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error {
	if err != nil || warn {
		msg := "You may have forgotten an attachment."
		if err != nil {
			logging.Warnf("failed to check for a forgotten attachment: %v", err)
			log.Warnf("failed to check for a forgotten attachment: %v", err)
			msg = "Failed to check for a forgotten attachment."
		}

@@ -148,7 +148,7 @@ func send(aerc *widgets.Aerc, composer *widgets.Composer, ctx sendCtx,
	failCh := make(chan error)
	// writer
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		var sender io.WriteCloser
		var err error
@@ -182,7 +182,7 @@ func send(aerc *widgets.Aerc, composer *widgets.Composer, ctx sendCtx,

	// cleanup + copy to sent
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		// leave no-quit mode
		defer mode.NoQuitDone()
diff --git a/commands/exec.go b/commands/exec.go
index 8757a51a6e04..37274116d660 100644
--- a/commands/exec.go
+++ b/commands/exec.go
@@ -7,7 +7,7 @@ import (
	"os/exec"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/widgets"
)

@@ -46,7 +46,7 @@ func (ExecCmd) Execute(aerc *widgets.Aerc, args []string) error {
	cmd.Env = env

	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		err := cmd.Run()
		if err != nil {
diff --git a/commands/history.go b/commands/history.go
index 5cc0bfb3caf7..7aa42fab6e1e 100644
--- a/commands/history.go
+++ b/commands/history.go
@@ -9,7 +9,7 @@ import (
	"path"
	"sync"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/kyoh86/xdg"
)

@@ -105,7 +105,7 @@ func (h *cmdHistory) initialize() {
		0o600,
	)
	if err != nil {
		logging.Errorf("failed to open history file: %v", err)
		log.Errorf("failed to open history file: %v", err)
		// basically mirror the old behavior
		h.histfile = bytes.NewBuffer([]byte{})
		return
diff --git a/commands/msg/archive.go b/commands/msg/archive.go
index b0c7b038cf09..149d7a5f7ade 100644
--- a/commands/msg/archive.go
+++ b/commands/msg/archive.go
@@ -7,7 +7,7 @@ import (
	"sync"

	"git.sr.ht/~rjarry/aerc/commands"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -101,7 +101,7 @@ func (Archive) Execute(aerc *widgets.Aerc, args []string) error {
	}
	// we need to do that in the background, else we block the main thread
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		wg.Wait()
		if success {
diff --git a/commands/msg/envelope.go b/commands/msg/envelope.go
index 616798d840d0..1b16d16f5379 100644
--- a/commands/msg/envelope.go
+++ b/commands/msg/envelope.go
@@ -6,7 +6,7 @@ import (
	"strings"

	"git.sr.ht/~rjarry/aerc/lib/format"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~sircmpwn/getopt"
@@ -127,7 +127,7 @@ func parseHeader(msg *models.MessageInfo, fmtStr string) (result []string) {
		for hf.Next() {
			text, err := hf.Text()
			if err != nil {
				logging.Errorf(err.Error())
				log.Errorf(err.Error())
				text = hf.Value()
			}
			result = append(result,
diff --git a/commands/msg/forward.go b/commands/msg/forward.go
index 74ee6575282d..c0215aeec99e 100644
--- a/commands/msg/forward.go
+++ b/commands/msg/forward.go
@@ -15,7 +15,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/lib/format"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -74,7 +74,7 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error {
	if err != nil {
		return err
	}
	logging.Debugf("Forwarding email <%s>", msg.Envelope.MessageId)
	log.Debugf("Forwarding email <%s>", msg.Envelope.MessageId)

	h := &mail.Header{}
	subject := "Fwd: " + msg.Envelope.Subject
@@ -133,10 +133,10 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error {
		store.FetchFull([]uint32{msg.Uid}, func(fm *types.FullMessage) {
			tmpFile, err := os.Create(tmpFileName)
			if err != nil {
				logging.Warnf("failed to create temporary attachment: %v", err)
				log.Warnf("failed to create temporary attachment: %v", err)
				_, err = addTab()
				if err != nil {
					logging.Warnf("failed to add tab: %v", err)
					log.Warnf("failed to add tab: %v", err)
				}
				return
			}
@@ -144,7 +144,7 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error {
			defer tmpFile.Close()
			_, err = io.Copy(tmpFile, fm.Content.Reader)
			if err != nil {
				logging.Warnf("failed to write to tmpfile: %v", err)
				log.Warnf("failed to write to tmpfile: %v", err)
				return
			}
			composer, err := addTab()
@@ -194,7 +194,7 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error {
					}
					bs, err := msg.BodyStructure.PartAtIndex(p)
					if err != nil {
						logging.Errorf("cannot get PartAtIndex %v: %v", p, err)
						log.Errorf("cannot get PartAtIndex %v: %v", p, err)
						continue
					}
					store.FetchBodyPart(msg.Uid, p, func(reader io.Reader) {
@@ -208,7 +208,7 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error {
						err := composer.AddPartAttachment(name, mime, params, reader)
						mu.Unlock()
						if err != nil {
							logging.Errorf(err.Error())
							log.Errorf(err.Error())
							aerc.PushError(err.Error())
						}
					})
diff --git a/commands/msg/invite.go b/commands/msg/invite.go
index 4b2507f4b205..32251643625e 100644
--- a/commands/msg/invite.go
+++ b/commands/msg/invite.go
@@ -9,7 +9,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib/calendar"
	"git.sr.ht/~rjarry/aerc/lib/format"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"github.com/emersion/go-message/mail"
@@ -187,7 +187,7 @@ func (invite) Execute(aerc *widgets.Aerc, args []string) error {
		} else {
			err := addTab(cr)
			if err != nil {
				logging.Warnf("failed to add tab: %v", err)
				log.Warnf("failed to add tab: %v", err)
			}
		}
	})
diff --git a/commands/msg/pipe.go b/commands/msg/pipe.go
index 4a5a61686885..878fd18c95ef 100644
--- a/commands/msg/pipe.go
+++ b/commands/msg/pipe.go
@@ -10,7 +10,7 @@ import (
	"time"

	"git.sr.ht/~rjarry/aerc/commands"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/widgets"
	mboxer "git.sr.ht/~rjarry/aerc/worker/mbox"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -92,12 +92,12 @@ func (Pipe) Execute(aerc *widgets.Aerc, args []string) error {
			return
		}
		go func() {
			defer logging.PanicHandler()
			defer log.PanicHandler()

			defer pipe.Close()
			_, err := io.Copy(pipe, reader)
			if err != nil {
				logging.Errorf("failed to send data to pipe: %v", err)
				log.Errorf("failed to send data to pipe: %v", err)
			}
		}()
		err = ecmd.Run()
@@ -166,7 +166,7 @@ func (Pipe) Execute(aerc *widgets.Aerc, args []string) error {
		})

		go func() {
			defer logging.PanicHandler()
			defer log.PanicHandler()

			select {
			case <-done:
@@ -245,7 +245,7 @@ func newMessagesReader(messages []*types.FullMessage, useMbox bool) io.Reader {
				_, err = io.Copy(pw, msg.Content.Reader)
			}
			if err != nil {
				logging.Warnf("failed to write data: %v", err)
				log.Warnf("failed to write data: %v", err)
			}
		}
	}()
diff --git a/commands/msg/recall.go b/commands/msg/recall.go
index eb8195f8937e..d39f4dafdcd3 100644
--- a/commands/msg/recall.go
+++ b/commands/msg/recall.go
@@ -14,7 +14,7 @@ import (

	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -70,7 +70,7 @@ func (Recall) Execute(aerc *widgets.Aerc, args []string) error {
	if err != nil {
		return errors.Wrap(err, "Recall failed")
	}
	logging.Debugf("Recalling message <%s>", msgInfo.Envelope.MessageId)
	log.Debugf("Recalling message <%s>", msgInfo.Envelope.MessageId)

	composer, err := widgets.NewComposer(aerc, acct, aerc.Config(),
		acct.AccountConfig(), acct.Worker(), "", msgInfo.RFC822Headers,
@@ -185,7 +185,7 @@ func (Recall) Execute(aerc *widgets.Aerc, args []string) error {
					if md.IsSigned {
						err = composer.SetSign(md.IsSigned)
						if err != nil {
							logging.Warnf("failed to set signed state: %v", err)
							log.Warnf("failed to set signed state: %v", err)
						}
					}
				}
@@ -200,7 +200,7 @@ func (Recall) Execute(aerc *widgets.Aerc, args []string) error {
					}
					bs, err := msg.BodyStructure().PartAtIndex(p)
					if err != nil {
						logging.Warnf("cannot get PartAtIndex %v: %v", p, err)
						log.Warnf("cannot get PartAtIndex %v: %v", p, err)
						continue
					}
					msg.FetchBodyPart(p, func(reader io.Reader) {
@@ -214,7 +214,7 @@ func (Recall) Execute(aerc *widgets.Aerc, args []string) error {
						err := composer.AddPartAttachment(name, mime, params, reader)
						mu.Unlock()
						if err != nil {
							logging.Errorf(err.Error())
							log.Errorf(err.Error())
							aerc.PushError(err.Error())
						}
					})
diff --git a/commands/msg/reply.go b/commands/msg/reply.go
index bd57f4b19a02..066eaca340af 100644
--- a/commands/msg/reply.go
+++ b/commands/msg/reply.go
@@ -14,7 +14,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib/crypto"
	"git.sr.ht/~rjarry/aerc/lib/format"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"github.com/emersion/go-message/mail"
@@ -226,12 +226,12 @@ func (reply) Execute(aerc *widgets.Aerc, args []string) error {
				buf := new(bytes.Buffer)
				_, err := buf.ReadFrom(reader)
				if err != nil {
					logging.Warnf("failed to fetch bodypart: %v", err)
					log.Warnf("failed to fetch bodypart: %v", err)
				}
				original.Text = buf.String()
				err = addTab()
				if err != nil {
					logging.Warnf("failed to add tab: %v", err)
					log.Warnf("failed to add tab: %v", err)
				}
			})
			return nil
@@ -254,12 +254,12 @@ func (reply) Execute(aerc *widgets.Aerc, args []string) error {
			buf := new(bytes.Buffer)
			_, err := buf.ReadFrom(reader)
			if err != nil {
				logging.Warnf("failed to fetch bodypart: %v", err)
				log.Warnf("failed to fetch bodypart: %v", err)
			}
			original.Text = buf.String()
			err = addTab()
			if err != nil {
				logging.Warnf("failed to add tab: %v", err)
				log.Warnf("failed to add tab: %v", err)
			}
		})
		return nil
diff --git a/commands/msg/unsubscribe.go b/commands/msg/unsubscribe.go
index 72c839fe1ae7..0538b2f28917 100644
--- a/commands/msg/unsubscribe.go
+++ b/commands/msg/unsubscribe.go
@@ -10,7 +10,7 @@ import (

	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"github.com/emersion/go-message/mail"
@@ -56,10 +56,10 @@ func (Unsubscribe) Execute(aerc *widgets.Aerc, args []string) error {
	if len(methods) == 0 {
		return fmt.Errorf("no methods found to unsubscribe")
	}
	logging.Debugf("unsubscribe: found %d methods", len(methods))
	log.Debugf("unsubscribe: found %d methods", len(methods))

	unsubscribe := func(method *url.URL) {
		logging.Debugf("unsubscribe: trying to unsubscribe using %s", method.Scheme)
		log.Debugf("unsubscribe: trying to unsubscribe using %s", method.Scheme)
		var err error
		switch strings.ToLower(method.Scheme) {
		case "mailto":
diff --git a/commands/msgview/save.go b/commands/msgview/save.go
index 4820ec0f6652..3cb48c2bcbbc 100644
--- a/commands/msgview/save.go
+++ b/commands/msgview/save.go
@@ -13,7 +13,7 @@ import (
	"github.com/mitchellh/go-homedir"

	"git.sr.ht/~rjarry/aerc/commands"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
)
@@ -164,7 +164,7 @@ func savePart(

	// we need to wait for the callback prior to displaying a result
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		err := <-ch
		if err != nil {
diff --git a/commands/util.go b/commands/util.go
index b14e96909e7d..fe0b2756ae2a 100644
--- a/commands/util.go
+++ b/commands/util.go
@@ -13,7 +13,7 @@ import (
	"github.com/lithammer/fuzzysearch/fuzzy"

	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/widgets"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -53,7 +53,7 @@ func QuickTerm(aerc *widgets.Aerc, args []string, stdin io.Reader) (*widgets.Ter
		status := make(chan error, 1)

		go func() {
			defer logging.PanicHandler()
			defer log.PanicHandler()

			_, err := io.Copy(pipe, stdin)
			defer pipe.Close()
diff --git a/completer/completer.go b/completer/completer.go
index 131063e78859..9b237fa8d419 100644
--- a/completer/completer.go
+++ b/completer/completer.go
@@ -12,7 +12,7 @@ import (
	"strings"
	"syscall"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/google/shlex"
)

@@ -110,7 +110,7 @@ func (c *Completer) completeAddress(s string) ([]string, string, error) {
		// make sure to kill the process *and* all its children
		//nolint:errcheck // who cares?
		syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
		logging.Warnf("command %s killed: %s", cmd, err)
		log.Warnf("command %s killed: %s", cmd, err)
	}
	if err != nil && !errors.Is(err, tooManyLines) {
		buf, _ := io.ReadAll(stderr)
@@ -176,8 +176,7 @@ func readCompletions(r io.Reader) ([]string, error) {
		parts := strings.SplitN(line, "\t", 3)
		addr, err := mail.ParseAddress(strings.TrimSpace(parts[0]))
		if err != nil {
			logging.Warnf(
				"line %d: %#v: could not parse address: %v",
			log.Warnf("line %d: %#v: could not parse address: %v",
				line, err)
			continue
		}
@@ -186,8 +185,7 @@ func readCompletions(r io.Reader) ([]string, error) {
		}
		decoded, err := decodeMIME(addr.String())
		if err != nil {
			logging.Warnf(
				"line %d: %#v: could not decode MIME string: %v",
			log.Warnf("line %d: %#v: could not decode MIME string: %v",
				i+1, line, err)
			continue
		}
diff --git a/config/accounts.go b/config/accounts.go
index b33bdf09ed8c..61f0e2823256 100644
--- a/config/accounts.go
+++ b/config/accounts.go
@@ -13,7 +13,7 @@ import (
	"strings"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/go-ini/ini"
)

@@ -112,7 +112,7 @@ func (config *AercConfig) parseAccounts(root string, accts []string) error {
		}
	}

	logging.Debugf("Parsing accounts configuration from %s", filename)
	log.Debugf("Parsing accounts configuration from %s", filename)

	file, err := ini.Load(filename)
	if err != nil {
@@ -216,7 +216,7 @@ func (config *AercConfig) parseAccounts(root string, accts []string) error {
			return fmt.Errorf("Invalid outgoing credentials for %s: %w", _sec, err)
		}

		logging.Debugf("accounts.conf: [%s] from = %s", account.Name, account.From)
		log.Debugf("accounts.conf: [%s] from = %s", account.Name, account.From)
		config.Accounts = append(config.Accounts, account)
	}
	if len(accts) > 0 {
diff --git a/config/binds.go b/config/binds.go
index 281aebf6881b..6ddeb1e1270a 100644
--- a/config/binds.go
+++ b/config/binds.go
@@ -10,7 +10,7 @@ import (
	"regexp"
	"strings"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/gdamore/tcell/v2"
	"github.com/go-ini/ini"
)
@@ -77,7 +77,7 @@ func (config *AercConfig) parseBinds(root string) error {
			return err
		}
	}
	logging.Debugf("Parsing key bindings configuration from %s", filename)
	log.Debugf("Parsing key bindings configuration from %s", filename)
	binds, err := ini.Load(filename)
	if err != nil {
		return err
@@ -122,7 +122,7 @@ func (config *AercConfig) parseBinds(root string) error {
		}
	}

	logging.Debugf("binds.conf: %#v", config.Bindings)
	log.Debugf("binds.conf: %#v", config.Bindings)
	return nil
}

@@ -212,7 +212,7 @@ func (config *AercConfig) LoadBinds(binds *ini.File, baseName string, baseGroup
				}
			}
			if !valid {
				logging.Warnf("binds.conf: unexistent account: %s", acctName)
				log.Warnf("binds.conf: unexistent account: %s", acctName)
				continue
			}
			contextualBind.ContextType = BIND_CONTEXT_ACCOUNT
diff --git a/config/compose.go b/config/compose.go
index f9c1ba90b840..cf9c9b584f31 100644
--- a/config/compose.go
+++ b/config/compose.go
@@ -4,7 +4,7 @@ import (
	"fmt"
	"regexp"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/go-ini/ini"
)

@@ -55,6 +55,6 @@ func (config *AercConfig) parseCompose(file *ini.File) error {
	}

end:
	logging.Debugf("aerc.conf: [compose] %#v", config.Compose)
	log.Debugf("aerc.conf: [compose] %#v", config.Compose)
	return nil
}
diff --git a/config/filters.go b/config/filters.go
index ffa203f96c9b..2b5a0c84d650 100644
--- a/config/filters.go
+++ b/config/filters.go
@@ -4,7 +4,7 @@ import (
	"regexp"
	"strings"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/go-ini/ini"
)

@@ -62,6 +62,6 @@ func (config *AercConfig) parseFilters(file *ini.File) error {
	}

end:
	logging.Debugf("aerc.conf: [filters] %#v", config.Filters)
	log.Debugf("aerc.conf: [filters] %#v", config.Filters)
	return nil
}
diff --git a/config/general.go b/config/general.go
index 2a462a3e6ff0..8ca224719e24 100644
--- a/config/general.go
+++ b/config/general.go
@@ -4,25 +4,25 @@ import (
	"fmt"
	"os"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/go-ini/ini"
	"github.com/mattn/go-isatty"
	"github.com/mitchellh/go-homedir"
)

type GeneralConfig struct {
	DefaultSavePath    string           `ini:"default-save-path"`
	PgpProvider        string           `ini:"pgp-provider"`
	UnsafeAccountsConf bool             `ini:"unsafe-accounts-conf"`
	LogFile            string           `ini:"log-file"`
	LogLevel           logging.LogLevel `ini:"-"`
	DefaultSavePath    string       `ini:"default-save-path"`
	PgpProvider        string       `ini:"pgp-provider"`
	UnsafeAccountsConf bool         `ini:"unsafe-accounts-conf"`
	LogFile            string       `ini:"log-file"`
	LogLevel           log.LogLevel `ini:"-"`
}

func defaultGeneralConfig() GeneralConfig {
	return GeneralConfig{
		PgpProvider:        "internal",
		UnsafeAccountsConf: false,
		LogLevel:           logging.INFO,
		LogLevel:           log.INFO,
	}
}

@@ -39,7 +39,7 @@ func (config *AercConfig) parseGeneral(file *ini.File) error {
	}
	level, err = gen.GetKey("log-level")
	if err == nil {
		l, err := logging.ParseLevel(level.String())
		l, err := log.ParseLevel(level.String())
		if err != nil {
			return err
		}
@@ -52,7 +52,7 @@ end:
	if !isatty.IsTerminal(os.Stdout.Fd()) {
		logFile = os.Stdout
		// redirected to file, force DEBUG level
		config.General.LogLevel = logging.DEBUG
		config.General.LogLevel = log.DEBUG
	} else if config.General.LogFile != "" {
		path, err := homedir.Expand(config.General.LogFile)
		if err != nil {
@@ -64,8 +64,8 @@ end:
			return fmt.Errorf("log-file: %w", err)
		}
	}
	logging.Init(logFile, config.General.LogLevel)
	logging.Debugf("aerc.conf: [general] %#v", config.General)
	log.Init(logFile, config.General.LogLevel)
	log.Debugf("aerc.conf: [general] %#v", config.General)
	return nil
}

diff --git a/config/openers.go b/config/openers.go
index d41c5455367e..c62ec974e804 100644
--- a/config/openers.go
+++ b/config/openers.go
@@ -3,7 +3,7 @@ package config
import (
	"strings"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/go-ini/ini"
	"github.com/google/shlex"
)
@@ -24,6 +24,6 @@ func (config *AercConfig) parseOpeners(file *ini.File) error {
	}

out:
	logging.Debugf("aerc.conf: [openers] %#v", config.Openers)
	log.Debugf("aerc.conf: [openers] %#v", config.Openers)
	return nil
}
diff --git a/config/statusline.go b/config/statusline.go
index a289c84de5b3..1e7d723eb8b5 100644
--- a/config/statusline.go
+++ b/config/statusline.go
@@ -1,7 +1,7 @@
package config

import (
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/go-ini/ini"
)

@@ -28,6 +28,6 @@ func (config *AercConfig) parseStatusline(file *ini.File) error {
		return err
	}
out:
	logging.Debugf("aerc.conf: [statusline] %#v", config.Statusline)
	log.Debugf("aerc.conf: [statusline] %#v", config.Statusline)
	return nil
}
diff --git a/config/templates.go b/config/templates.go
index 2f581e44249f..32d838fc76b9 100644
--- a/config/templates.go
+++ b/config/templates.go
@@ -5,7 +5,7 @@ import (
	"strings"

	"git.sr.ht/~rjarry/aerc/lib/templates"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/go-ini/ini"
)

@@ -56,7 +56,7 @@ func (config *AercConfig) parseTemplates(file *ini.File) error {
		return err
	}

	logging.Debugf("aerc.conf: [templates] %#v", config.Templates)
	log.Debugf("aerc.conf: [templates] %#v", config.Templates)

	return nil
}
diff --git a/config/triggers.go b/config/triggers.go
index af400501b6ff..2a357bc0f84c 100644
--- a/config/triggers.go
+++ b/config/triggers.go
@@ -8,7 +8,7 @@ import (
	"github.com/google/shlex"

	"git.sr.ht/~rjarry/aerc/lib/format"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
)

@@ -26,7 +26,7 @@ func (config *AercConfig) parseTriggers(file *ini.File) error {
		return err
	}
out:
	logging.Debugf("aerc.conf: [triggers] %#v", config.Triggers)
	log.Debugf("aerc.conf: [triggers] %#v", config.Triggers)
	return nil
}

@@ -74,6 +74,6 @@ func (trig *TriggersConfig) ExecNewEmail(account *AccountConfig,
			return fmt.Sprintf(formatstr, args...), nil
		})
	if err != nil {
		logging.Errorf("failed to run new-email trigger: %v", err)
		log.Errorf("failed to run new-email trigger: %v", err)
	}
}
diff --git a/config/ui.go b/config/ui.go
index 16a296dfd615..9af470859621 100644
--- a/config/ui.go
+++ b/config/ui.go
@@ -7,7 +7,7 @@ import (
	"strings"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/gdamore/tcell/v2"
	"github.com/go-ini/ini"
	"github.com/imdario/mergo"
@@ -211,7 +211,7 @@ func (config *AercConfig) parseUi(file *ini.File) error {
		}
	}

	logging.Debugf("aerc.conf: [ui] %#v", config.Ui)
	log.Debugf("aerc.conf: [ui] %#v", config.Ui)

	return nil
}
@@ -294,7 +294,7 @@ func (config *AercConfig) mergeContextualUi(baseUi UIConfig,

		err := mergo.Merge(&baseUi, contextualUi.UiConfig, mergo.WithOverride)
		if err != nil {
			logging.Warnf("merge ui failed: %v", err)
			log.Warnf("merge ui failed: %v", err)
		}
		if contextualUi.UiConfig.StyleSetName != "" {
			baseUi.style = contextualUi.UiConfig.style
diff --git a/config/viewer.go b/config/viewer.go
index fe93f389d193..c00e62f4554f 100644
--- a/config/viewer.go
+++ b/config/viewer.go
@@ -3,7 +3,7 @@ package config
import (
	"strings"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/go-ini/ini"
)

@@ -49,6 +49,6 @@ func (config *AercConfig) parseViewer(file *ini.File) error {
		}
	}
out:
	logging.Debugf("aerc.conf: [viewer] %#v", config.Viewer)
	log.Debugf("aerc.conf: [viewer] %#v", config.Viewer)
	return nil
}
diff --git a/doc/aerc.1.scd b/doc/aerc.1.scd
index 04ca89f1ccb0..5b5add892a8b 100644
--- a/doc/aerc.1.scd
+++ b/doc/aerc.1.scd
@@ -571,7 +571,7 @@ Aerc does not log by default, but collecting log output can be useful for
troubleshooting and reporting issues. Redirecting stdout when invoking aerc will
write log messages to that file:

	$ aerc > log
	$ aerc > aerc.log

Persistent logging can be configured via the *log-file* and *log-level* settings
in _aerc.conf_.
diff --git a/lib/attachment.go b/lib/attachment.go
index e926dfa94bce..5c2284f5688c 100644
--- a/lib/attachment.go
+++ b/lib/attachment.go
@@ -10,7 +10,7 @@ import (
	"path/filepath"
	"strings"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/emersion/go-message/mail"
	"github.com/pkg/errors"
)
@@ -153,7 +153,7 @@ func SetUtf8Charset(origParams map[string]string) map[string]string {
	for k, v := range origParams {
		switch strings.ToLower(k) {
		case "charset":
			logging.Debugf("substitute charset %s with utf-8", v)
			log.Debugf("substitute charset %s with utf-8", v)
			params[k] = "utf-8"
		default:
			params[k] = v
diff --git a/lib/crypto/gpg/gpgbin/gpgbin.go b/lib/crypto/gpg/gpgbin/gpgbin.go
index d83c45fb2884..a83ebb37ff21 100644
--- a/lib/crypto/gpg/gpgbin/gpgbin.go
+++ b/lib/crypto/gpg/gpgbin/gpgbin.go
@@ -10,7 +10,7 @@ import (
	"strconv"
	"strings"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
)

@@ -65,7 +65,7 @@ func getIdentity(key uint64) string {
	cmd.Stdout = &outbuf
	err := cmd.Run()
	if err != nil {
		logging.Errorf("gpg: failed to get identity: %v", err)
		log.Errorf("gpg: failed to get identity: %v", err)
		return ""
	}
	out := strings.Split(outbuf.String(), "\n")
@@ -91,7 +91,7 @@ func getKeyId(s string, private bool) string {
	cmd.Stdout = &outbuf
	err := cmd.Run()
	if err != nil {
		logging.Errorf("gpg: failed to get key ID: %v", err)
		log.Errorf("gpg: failed to get key ID: %v", err)
		return ""
	}
	out := strings.Split(outbuf.String(), "\n")
@@ -129,7 +129,7 @@ func parse(r io.Reader, md *models.MessageDetails) error {
		}
		if strings.HasPrefix(line, "[GNUPG:]") {
			msgCollecting = false
			logging.Tracef(line)
			log.Tracef(line)
		}
		if msgCollecting {
			msgContent = append(msgContent, scanner.Bytes()...)
diff --git a/lib/crypto/pgp/pgp.go b/lib/crypto/pgp/pgp.go
index fd9d13eb470c..b2f5fa241e7b 100644
--- a/lib/crypto/pgp/pgp.go
+++ b/lib/crypto/pgp/pgp.go
@@ -9,7 +9,7 @@ import (
	"strings"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"github.com/ProtonMail/go-crypto/openpgp"
	"github.com/ProtonMail/go-crypto/openpgp/armor"
@@ -29,7 +29,7 @@ var (
)

func (m *Mail) Init() error {
	logging.Debugf("Initializing PGP keyring")
	log.Debugf("Initializing PGP keyring")
	err := os.MkdirAll(path.Join(xdg.DataHome(), "aerc"), 0o700)
	if err != nil {
		return fmt.Errorf("failed to create data directory: %w", err)
diff --git a/lib/messageview.go b/lib/messageview.go
index 8507880be0b4..d7ff1908e0fb 100644
--- a/lib/messageview.go
+++ b/lib/messageview.go
@@ -10,7 +10,7 @@ import (
	_ "github.com/emersion/go-message/charset"

	"git.sr.ht/~rjarry/aerc/lib/crypto"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/lib"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -158,9 +158,9 @@ func (msv *MessageStoreView) FetchBodyPart(part []int, cb func(io.Reader)) {
	reader, err := lib.FetchEntityPartReader(msg, part)
	if err != nil {
		errMsg := fmt.Errorf("Failed to fetch message part: %w", err)
		logging.Errorf(errMsg.Error())
		log.Errorf(errMsg.Error())
		if msv.message != nil {
			logging.Warnf("Displaying raw message part")
			log.Warnf("Displaying raw message part")
			reader = bytes.NewReader(msv.message)
		} else {
			reader = strings.NewReader(errMsg.Error())
diff --git a/lib/msgstore.go b/lib/msgstore.go
index 4205ea109536..4a68f808e8e6 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -9,7 +9,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib/marker"
	"git.sr.ht/~rjarry/aerc/lib/sort"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -420,7 +420,7 @@ func (store *MessageStore) runThreadBuilder() {
	}
	if store.threadBuilderDebounce != nil {
		if store.threadBuilderDebounce.Stop() {
			logging.Tracef("thread builder debounced")
			log.Tracef("thread builder debounced")
		}
	}
	store.threadBuilderDebounce = time.AfterFunc(store.threadBuilderDelay, func() {
@@ -469,7 +469,7 @@ func (store *MessageStore) SelectedThread() *types.Thread {
			return nil
		})
		if err != nil {
			logging.Errorf("SelectedThread failed: %v", err)
			log.Errorf("SelectedThread failed: %v", err)
		}
		if found {
			break
diff --git a/lib/open.go b/lib/open.go
index 9faa6d1021dc..2a4bdbcfbe88 100644
--- a/lib/open.go
+++ b/lib/open.go
@@ -6,7 +6,7 @@ import (
	"runtime"
	"strings"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
)

func XDGOpen(uri string) error {
@@ -46,10 +46,10 @@ func XDGOpenMime(
		args = append(args, uri)
	}

	logging.Tracef("running command: %v", args)
	log.Tracef("running command: %v", args)
	cmd := exec.Command(args[0], args[1:]...)
	out, err := cmd.CombinedOutput()
	logging.Debugf("command: %v exited. err=%v out=%s", args, err, out)
	log.Debugf("command: %v exited. err=%v out=%s", args, err, out)
	if err != nil {
		return fmt.Errorf("%v: %w", args, err)
	}
diff --git a/lib/parse/ansi.go b/lib/parse/ansi.go
index 265ef1f4924b..e1d603eab5cd 100644
--- a/lib/parse/ansi.go
+++ b/lib/parse/ansi.go
@@ -8,7 +8,7 @@ import (
	"os"
	"regexp"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
)

var ansi = regexp.MustCompile("\x1B\\[[0-?]*[ -/]*[@-~]")
@@ -23,11 +23,11 @@ func StripAnsi(r io.Reader) io.Reader {
		line = ansi.ReplaceAll(line, []byte(""))
		_, err := buf.Write(line)
		if err != nil {
			logging.Warnf("failed write ", err)
			log.Warnf("failed write ", err)
		}
		_, err = buf.Write([]byte("\n"))
		if err != nil {
			logging.Warnf("failed write ", err)
			log.Warnf("failed write ", err)
		}
	}
	if err := scanner.Err(); err != nil {
diff --git a/lib/socket.go b/lib/socket.go
index 1cfd0583e62a..5a41d9102d22 100644
--- a/lib/socket.go
+++ b/lib/socket.go
@@ -12,7 +12,7 @@ import (
	"sync/atomic"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/kyoh86/xdg"
)

@@ -28,7 +28,7 @@ func StartServer() (*AercServer, error) {
	if err := ConnectAndExec(""); err != nil {
		os.Remove(sockpath)
	}
	logging.Debugf("Starting Unix server: %s", sockpath)
	log.Debugf("Starting Unix server: %s", sockpath)
	l, err := net.Listen("unix", sockpath)
	if err != nil {
		return nil, err
@@ -36,7 +36,7 @@ func StartServer() (*AercServer, error) {
	as := &AercServer{listener: l}
	// TODO: stash clients and close them on exit... bleh racey
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		for {
			conn, err := l.Accept()
@@ -46,12 +46,12 @@ func StartServer() (*AercServer, error) {
					// TODO: Something more useful, in some
					// cases, on wednesdays, after 2 PM,
					// I guess?
					logging.Errorf("Closing Unix server: %v", err)
					log.Errorf("Closing Unix server: %v", err)
				}
				return
			}
			go func() {
				defer logging.PanicHandler()
				defer log.PanicHandler()

				as.handleClient(conn)
			}()
@@ -68,23 +68,23 @@ var lastId int64 = 0 // access via atomic

func (as *AercServer) handleClient(conn net.Conn) {
	clientId := atomic.AddInt64(&lastId, 1)
	logging.Debugf("unix:%d accepted connection", clientId)
	log.Debugf("unix:%d accepted connection", clientId)
	scanner := bufio.NewScanner(conn)
	err := conn.SetDeadline(time.Now().Add(1 * time.Minute))
	if err != nil {
		logging.Errorf("failed to set deadline: %v", err)
		log.Errorf("failed to set deadline: %v", err)
	}
	for scanner.Scan() {
		err = conn.SetDeadline(time.Now().Add(1 * time.Minute))
		if err != nil {
			logging.Errorf("failed to update deadline: %v", err)
			log.Errorf("failed to update deadline: %v", err)
		}
		msg := scanner.Text()
		logging.Tracef("unix:%d got message %s", clientId, msg)
		log.Tracef("unix:%d got message %s", clientId, msg)
		if !strings.ContainsRune(msg, ':') {
			_, innererr := conn.Write([]byte("error: invalid command\n"))
			if innererr != nil {
				logging.Errorf("failed to write error message: %v", innererr)
				log.Errorf("failed to write error message: %v", innererr)
			}
			continue
		}
@@ -96,14 +96,14 @@ func (as *AercServer) handleClient(conn net.Conn) {
			if err != nil {
				_, innererr := conn.Write([]byte(fmt.Sprintf("error: %v\n", err)))
				if innererr != nil {
					logging.Errorf("failed to write error message: %v", innererr)
					log.Errorf("failed to write error message: %v", innererr)
				}
				break
			}
			if as.OnMailto != nil {
				err = as.OnMailto(mailto)
				if err != nil {
					logging.Errorf("mailto failed: %v", err)
					log.Errorf("mailto failed: %v", err)
				}
			}
		case "mbox":
@@ -114,16 +114,16 @@ func (as *AercServer) handleClient(conn net.Conn) {
		if err != nil {
			_, err = conn.Write([]byte(fmt.Sprintf("result: %v\n", err)))
			if err != nil {
				logging.Errorf("failed to send error: %v")
				log.Errorf("failed to send error: %v")
			}
		} else {
			_, err = conn.Write([]byte("result: success\n"))
			if err != nil {
				logging.Errorf("failed to send successmessage: %v")
				log.Errorf("failed to send successmessage: %v")
			}
		}
	}
	logging.Tracef("unix:%d closed connection", clientId)
	log.Tracef("unix:%d closed connection", clientId)
}

func ConnectAndExec(msg string) error {
diff --git a/lib/threadbuilder.go b/lib/threadbuilder.go
index 34f143a41390..5a73397a29ad 100644
--- a/lib/threadbuilder.go
+++ b/lib/threadbuilder.go
@@ -5,7 +5,7 @@ import (
	"time"

	"git.sr.ht/~rjarry/aerc/lib/iterator"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
	"github.com/gatherstars-com/jwz"
@@ -67,7 +67,7 @@ func (builder *ThreadBuilder) Threads(uids []uint32, inverse bool, sort bool,
	builder.RebuildUids(threads, inverse)

	elapsed := time.Since(start)
	logging.Tracef("%d threads from %d uids created in %s", len(threads),
	log.Tracef("%d threads from %d uids created in %s", len(threads),
		len(uids), elapsed)

	return threads
@@ -84,7 +84,7 @@ func (builder *ThreadBuilder) generateStructure(uids []uint32) jwz.Threadable {
	threader := jwz.NewThreader()
	threadStructure, err := threader.ThreadSlice(jwzThreads)
	if err != nil {
		logging.Errorf("failed slicing threads: %v", err)
		log.Errorf("failed slicing threads: %v", err)
	}
	return threadStructure
}
diff --git a/lib/ui/textinput.go b/lib/ui/textinput.go
index 8880c4c3e793..bcfe4a838d7f 100644
--- a/lib/ui/textinput.go
+++ b/lib/ui/textinput.go
@@ -10,7 +10,7 @@ import (
	"github.com/mattn/go-runewidth"

	"git.sr.ht/~rjarry/aerc/config"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
)

// TODO: Attach history providers
@@ -298,7 +298,7 @@ func (ti *TextInput) updateCompletions() {
	}
	if ti.completeDebouncer == nil {
		ti.completeDebouncer = time.AfterFunc(ti.completeDelay, func() {
			defer logging.PanicHandler()
			defer log.PanicHandler()
			ti.Lock()
			if len(ti.StringLeft()) >= ti.completeMinChars {
				ti.showCompletions()
diff --git a/logging/logger.go b/log/logger.go
similarity index 99%
rename from logging/logger.go
rename to log/logger.go
index 8dc4ef6b9dfe..eb52d7b74233 100644
--- a/logging/logger.go
+++ b/log/logger.go
@@ -1,4 +1,4 @@
package logging
package log

import (
	"fmt"
diff --git a/logging/panic-logger.go b/log/panic-logger.go
similarity index 98%
rename from logging/panic-logger.go
rename to log/panic-logger.go
index 11b1803e3053..a19044151a5c 100644
--- a/logging/panic-logger.go
+++ b/log/panic-logger.go
@@ -1,4 +1,4 @@
package logging
package log

import (
	"fmt"
diff --git a/widgets/account.go b/widgets/account.go
index ca899c939f71..c8c58b1e991d 100644
--- a/widgets/account.go
+++ b/widgets/account.go
@@ -14,7 +14,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib/sort"
	"git.sr.ht/~rjarry/aerc/lib/statusline"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -83,7 +83,7 @@ func NewAccountView(aerc *Aerc, conf *config.AercConfig, acct *config.AccountCon
	worker, err := worker.NewWorker(acct.Source, acct.Name)
	if err != nil {
		host.SetError(fmt.Sprintf("%s: %s", acct.Name, err))
		logging.Errorf("%s: %v", acct.Name, err)
		log.Errorf("%s: %v", acct.Name, err)
		return view, err
	}
	view.worker = worker
@@ -97,7 +97,7 @@ func NewAccountView(aerc *Aerc, conf *config.AercConfig, acct *config.AccountCon
	view.grid.AddChild(view.msglist).At(0, 1)

	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		if deferLoop != nil {
			<-deferLoop
@@ -235,7 +235,7 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
		switch msg.InResponseTo().(type) {
		case *types.Connect, *types.Reconnect:
			acct.SetStatus(statusline.ConnectionActivity("Listing mailboxes..."))
			logging.Tracef("Listing mailboxes...")
			log.Tracef("Listing mailboxes...")
			acct.dirlist.UpdateList(func(dirs []string) {
				var dir string
				for _, _dir := range dirs {
@@ -251,14 +251,14 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
					acct.dirlist.Select(dir)
				}
				acct.msglist.SetInitDone()
				logging.Infof("[%s] connected.", acct.acct.Name)
				log.Infof("[%s] connected.", acct.acct.Name)
				acct.SetStatus(statusline.SetConnected(true))
				acct.newConn = true
			})
		case *types.Disconnect:
			acct.dirlist.ClearList()
			acct.msglist.SetStore(nil)
			logging.Infof("[%s] disconnected.", acct.acct.Name)
			log.Infof("[%s] disconnected.", acct.acct.Name)
			acct.SetStatus(statusline.SetConnected(false))
		case *types.OpenDirectory:
			if store, ok := acct.dirlist.SelectedMsgStore(); ok {
@@ -347,13 +347,13 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
	case *types.LabelList:
		acct.labels = msg.Labels
	case *types.ConnError:
		logging.Errorf("[%s] connection error: %v", acct.acct.Name, msg.Error)
		log.Errorf("[%s] connection error: %v", acct.acct.Name, msg.Error)
		acct.SetStatus(statusline.SetConnected(false))
		acct.PushError(msg.Error)
		acct.msglist.SetStore(nil)
		acct.worker.PostAction(&types.Reconnect{}, nil)
	case *types.Error:
		logging.Errorf("[%s] unexpected error: %v", acct.acct.Name, msg.Error)
		log.Errorf("[%s] unexpected error: %v", acct.acct.Name, msg.Error)
		acct.PushError(msg.Error)
	}
	acct.UpdateStatus()
@@ -427,7 +427,7 @@ func (acct *AccountView) CheckMail() {
	dirs := acct.dirlist.List()
	dirs = acct.dirlist.FilterDirs(dirs, acct.AccountConfig().CheckMailInclude, false)
	dirs = acct.dirlist.FilterDirs(dirs, exclude, true)
	logging.Debugf("Checking for new mail on account %s", acct.Name())
	log.Debugf("Checking for new mail on account %s", acct.Name())
	acct.SetStatus(statusline.ConnectionActivity("Checking for new mail..."))
	msg := &types.CheckMail{
		Directories: dirs,
diff --git a/widgets/aerc.go b/widgets/aerc.go
index dce28c3e77f6..ca82ee28a95b 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -19,7 +19,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/lib/crypto"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -139,11 +139,11 @@ func (aerc *Aerc) OnBeep(f func() error) {

func (aerc *Aerc) Beep() {
	if aerc.beep == nil {
		logging.Warnf("should beep, but no beeper")
		log.Warnf("should beep, but no beeper")
		return
	}
	if err := aerc.beep(); err != nil {
		logging.Errorf("tried to beep, but could not: %v", err)
		log.Errorf("tried to beep, but could not: %v", err)
	}
}

@@ -750,7 +750,7 @@ func (aerc *Aerc) Mbox(source string) error {
		acctConf = *selectedAcct.acct
		info := fmt.Sprintf("Loading outgoing mbox mail settings from account [%s]", selectedAcct.Name())
		aerc.PushStatus(info, 10*time.Second)
		logging.Debugf(info)
		log.Debugf(info)
	} else {
		acctConf.From = "<user@localhost>"
	}
@@ -782,7 +782,7 @@ func (aerc *Aerc) CloseBackends() error {
		err := c.Close()
		if err != nil {
			returnErr = err
			logging.Errorf("Closing backend failed for %s: %v", acct.Name(), err)
			log.Errorf("Closing backend failed for %s: %v", acct.Name(), err)
		}
	}
	return returnErr
diff --git a/widgets/compose.go b/widgets/compose.go
index 1bbdb477cf0b..c52c381fb145 100644
--- a/widgets/compose.go
+++ b/widgets/compose.go
@@ -23,7 +23,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib/format"
	"git.sr.ht/~rjarry/aerc/lib/templates"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -109,7 +109,7 @@ func NewComposer(aerc *Aerc, acct *AccountView, conf *config.AercConfig,

func (c *Composer) SwitchAccount(newAcct *AccountView) error {
	if c.acct == newAcct {
		logging.Tracef("same accounts: no switch")
		log.Tracef("same accounts: no switch")
		return nil
	}
	// sync the header with the editors
@@ -127,7 +127,7 @@ func (c *Composer) SwitchAccount(newAcct *AccountView) error {
		editor.loadValue()
	}
	c.Invalidate()
	logging.Debugf("account sucessfully switched")
	log.Debugf("account sucessfully switched")
	return nil
}

@@ -158,7 +158,7 @@ func (c *Composer) setupFor(acct *AccountView) error {
	cmpl := completer.New(cmd, func(err error) {
		c.aerc.PushError(
			fmt.Sprintf("could not complete header: %v", err))
		logging.Errorf("could not complete header: %v", err)
		log.Errorf("could not complete header: %v", err)
	})
	c.completer = cmpl

@@ -188,7 +188,7 @@ func (c *Composer) setupFor(acct *AccountView) error {
	c.sign = false
	if c.acctConfig.PgpAutoSign {
		err := c.SetSign(true)
		logging.Warnf("failed to enable message signing: %v", err)
		log.Warnf("failed to enable message signing: %v", err)
	}
	c.encrypt = false
	if c.acctConfig.PgpOpportunisticEncrypt {
@@ -196,7 +196,7 @@ func (c *Composer) setupFor(acct *AccountView) error {
	}
	err := c.updateCrypto()
	if err != nil {
		logging.Warnf("failed to update crypto: %v", err)
		log.Warnf("failed to update crypto: %v", err)
	}

	return nil
@@ -351,7 +351,7 @@ func (c *Composer) SetEncrypt(encrypt bool) *Composer {
		c.encrypt = encrypt
		err := c.updateCrypto()
		if err != nil {
			logging.Warnf("failed to update crypto: %v", err)
			log.Warnf("failed to update crypto: %v", err)
		}
		return c
	}
@@ -427,19 +427,19 @@ func (c *Composer) updateCrypto() error {
func (c *Composer) SetContents(reader io.Reader) *Composer {
	_, err := c.email.Seek(0, io.SeekStart)
	if err != nil {
		logging.Warnf("failed to seek beginning of mail: %v", err)
		log.Warnf("failed to seek beginning of mail: %v", err)
	}
	_, err = io.Copy(c.email, reader)
	if err != nil {
		logging.Warnf("failed to copy mail: %v", err)
		log.Warnf("failed to copy mail: %v", err)
	}
	err = c.email.Sync()
	if err != nil {
		logging.Warnf("failed to sync mail: %v", err)
		log.Warnf("failed to sync mail: %v", err)
	}
	_, err = c.email.Seek(0, io.SeekStart)
	if err != nil {
		logging.Warnf("failed to seek beginning of mail after sync: %v", err)
		log.Warnf("failed to seek beginning of mail after sync: %v", err)
	}
	return c
}
@@ -447,15 +447,15 @@ func (c *Composer) SetContents(reader io.Reader) *Composer {
func (c *Composer) AppendContents(reader io.Reader) {
	_, err := c.email.Seek(0, io.SeekEnd)
	if err != nil {
		logging.Warnf("failed to seek beginning of mail: %v", err)
		log.Warnf("failed to seek beginning of mail: %v", err)
	}
	_, err = io.Copy(c.email, reader)
	if err != nil {
		logging.Warnf("failed to copy mail: %v", err)
		log.Warnf("failed to copy mail: %v", err)
	}
	err = c.email.Sync()
	if err != nil {
		logging.Warnf("failed to sync mail: %v", err)
		log.Warnf("failed to sync mail: %v", err)
	}
}

@@ -1415,7 +1415,7 @@ func (c *Composer) checkEncryptionKeys(_ string) bool {
	c.encrypt = true
	err = c.updateCrypto()
	if err != nil {
		logging.Warnf("failed update crypto: %v", err)
		log.Warnf("failed update crypto: %v", err)
	}
	return true
}
diff --git a/widgets/dirlist.go b/widgets/dirlist.go
index 4663d487499f..e4f867eb94e0 100644
--- a/widgets/dirlist.go
+++ b/widgets/dirlist.go
@@ -18,7 +18,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/lib/format"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -155,7 +155,7 @@ func (dirlist *DirectoryList) Select(name string) {
	delay := dirlist.UiConfig(name).DirListDelay

	go func(ctx context.Context) {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		select {
		case <-time.After(delay):
@@ -187,7 +187,7 @@ func (dirlist *DirectoryList) Select(name string) {
				})
			dirlist.Invalidate()
		case <-ctx.Done():
			logging.Tracef("dirlist: skip %s", name)
			log.Tracef("dirlist: skip %s", name)
			return
		}
	}(ctx)
diff --git a/widgets/dirtree.go b/widgets/dirtree.go
index 8a3dab6f2ce0..e9fbf0614690 100644
--- a/widgets/dirtree.go
+++ b/widgets/dirtree.go
@@ -9,7 +9,7 @@ import (
	"git.sr.ht/~rjarry/aerc/config"
	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/worker/types"
	"github.com/gdamore/tcell/v2"
)
@@ -389,7 +389,7 @@ func (dt *DirectoryTree) buildTree() {
			return nil
		})
		if err != nil {
			logging.Warnf("failed to walk tree: %v", err)
			log.Warnf("failed to walk tree: %v", err)
		}
	}
}
@@ -455,7 +455,7 @@ func getAnyUid(node *types.Thread) (uid uint32) {
		return nil
	})
	if err != nil {
		logging.Warnf("failed to get uid: %v", err)
		log.Warnf("failed to get uid: %v", err)
	}
	return
}
diff --git a/widgets/listbox.go b/widgets/listbox.go
index 8f4f71232415..9a0a48bcaeba 100644
--- a/widgets/listbox.go
+++ b/widgets/listbox.go
@@ -7,7 +7,7 @@ import (

	"git.sr.ht/~rjarry/aerc/config"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/gdamore/tcell/v2"
	"github.com/mattn/go-runewidth"
)
@@ -58,7 +58,7 @@ func (lb *ListBox) dedup() {
	dedup := make(map[string]struct{})
	for _, line := range lb.lines {
		if _, dup := dedup[line]; dup {
			logging.Warnf("ignore duplicate: %s", line)
			log.Warnf("ignore duplicate: %s", line)
			continue
		}
		dedup[line] = struct{}{}
diff --git a/widgets/msglist.go b/widgets/msglist.go
index ef29724aaf7c..09ee705ef898 100644
--- a/widgets/msglist.go
+++ b/widgets/msglist.go
@@ -14,7 +14,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib/format"
	"git.sr.ht/~rjarry/aerc/lib/iterator"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -119,7 +119,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
					return nil
				})
			if err != nil {
				logging.Errorf("thread walk: %v", err)
				log.Errorf("thread walk: %v", err)
			}
			for curIter := factory.NewIterator(cur); curIter.Next(); {
				if i < ml.Scroll() {
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index 019f9d6ef8d0..6c929578bf56 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -20,7 +20,7 @@ import (
	"git.sr.ht/~rjarry/aerc/lib/format"
	"git.sr.ht/~rjarry/aerc/lib/parse"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
)

@@ -240,7 +240,7 @@ func createSwitcher(acct *AccountView, switcher *PartSwitcher,
			return err
		}
		selectedPriority := -1
		logging.Tracef("Selecting best message from %v", conf.Viewer.Alternatives)
		log.Tracef("Selecting best message from %v", conf.Viewer.Alternatives)
		for i, pv := range switcher.parts {
			// Switch to user's preferred mimetype
			if switcher.selected == -1 && pv.part.MIMEType != "multipart" {
@@ -312,7 +312,7 @@ func (mv *MessageViewer) ToggleHeaders() {
	mv.conf.Viewer.ShowHeaders = !mv.conf.Viewer.ShowHeaders
	err := createSwitcher(mv.acct, switcher, mv.conf, mv.msg)
	if err != nil {
		logging.Errorf("cannot create switcher: %v", err)
		log.Errorf("cannot create switcher: %v", err)
	}
	switcher.Invalidate()
}
@@ -603,7 +603,7 @@ func NewPartViewer(acct *AccountView, conf *config.AercConfig,
			fmt.Sprintf("AERC_SUBJECT=%s", info.Envelope.Subject))
		filter.Env = append(filter.Env, fmt.Sprintf("AERC_FROM=%s",
			format.FormatAddresses(info.Envelope.From)))
		logging.Debugf("<%s> part=%v %s: %v | %v",
		log.Debugf("<%s> part=%v %s: %v | %v",
			info.Envelope.MessageId, curindex, mime, filter, pager)
		if pagerin, err = pager.StdinPipe(); err != nil {
			return nil, err
@@ -668,20 +668,20 @@ func (pv *PartViewer) attemptCopy() {
	pv.filter.Stderr = pv.pagerin
	err := pv.filter.Start()
	if err != nil {
		logging.Errorf("error running filter: %v", err)
		log.Errorf("error running filter: %v", err)
		return
	}
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()
		defer atomic.StoreInt32(&pv.copying, 0)
		err = pv.filter.Wait()
		if err != nil {
			logging.Errorf("error waiting for filter: %v", err)
			log.Errorf("error waiting for filter: %v", err)
			return
		}
		err = pv.pagerin.Close()
		if err != nil {
			logging.Errorf("error closing pager pipe: %v", err)
			log.Errorf("error closing pager pipe: %v", err)
			return
		}
	}()
@@ -705,7 +705,7 @@ func (pv *PartViewer) writeMailHeaders() {
				"%s: %s\n", fields.Key(), value)
			_, err = pv.pagerin.Write([]byte(field))
			if err != nil {
				logging.Errorf("failed to write to stdin of pager: %v", err)
				log.Errorf("failed to write to stdin of pager: %v", err)
			}
		}
		// virtual header
@@ -713,12 +713,12 @@ func (pv *PartViewer) writeMailHeaders() {
			labels := fmtHeader(info, "Labels", "", "", "", "")
			_, err := pv.pagerin.Write([]byte(fmt.Sprintf("Labels: %s\n", labels)))
			if err != nil {
				logging.Errorf("failed to write to stdin of pager: %v", err)
				log.Errorf("failed to write to stdin of pager: %v", err)
			}
		}
		_, err := pv.pagerin.Write([]byte{'\n'})
		if err != nil {
			logging.Errorf("failed to write to stdin of pager: %v", err)
			log.Errorf("failed to write to stdin of pager: %v", err)
		}
	}
}
diff --git a/widgets/spinner.go b/widgets/spinner.go
index cddbacd59436..99365527d631 100644
--- a/widgets/spinner.go
+++ b/widgets/spinner.go
@@ -9,7 +9,7 @@ import (

	"git.sr.ht/~rjarry/aerc/config"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
)

type Spinner struct {
@@ -37,7 +37,7 @@ func (s *Spinner) Start() {
	atomic.StoreInt64(&s.frame, 0)

	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		for {
			select {
diff --git a/widgets/status.go b/widgets/status.go
index a6fd5c8fc96b..97ff9441c703 100644
--- a/widgets/status.go
+++ b/widgets/status.go
@@ -8,7 +8,7 @@ import (

	"git.sr.ht/~rjarry/aerc/config"
	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
)

type StatusLine struct {
@@ -76,7 +76,7 @@ func (status *StatusLine) Push(text string, expiry time.Duration) *StatusMessage
	}
	status.stack = append(status.stack, msg)
	go (func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		time.Sleep(expiry)
		for i, m := range status.stack {
diff --git a/widgets/terminal.go b/widgets/terminal.go
index b12a6a0a9428..9a2ebbef5398 100644
--- a/widgets/terminal.go
+++ b/widgets/terminal.go
@@ -5,7 +5,7 @@ import (
	"syscall"

	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	tcellterm "git.sr.ht/~rockorager/tcell-term"

	"github.com/gdamore/tcell/v2"
@@ -81,7 +81,7 @@ func (term *Terminal) Draw(ctx *ui.Context) {
		term.vterm.Watch(term)
		attr := &syscall.SysProcAttr{Setsid: true, Setctty: true, Ctty: 1}
		if err := term.vterm.StartWithAttrs(term.cmd, attr); err != nil {
			logging.Errorf("error running terminal: %v", err)
			log.Errorf("error running terminal: %v", err)
			term.Close(err)
			return
		}
diff --git a/worker/imap/cache.go b/worker/imap/cache.go
index cf92dfaafffd..a889f7252090 100644
--- a/worker/imap/cache.go
+++ b/worker/imap/cache.go
@@ -9,7 +9,7 @@ import (
	"path"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
	"github.com/emersion/go-message"
@@ -34,18 +34,18 @@ func (w *IMAPWorker) initCacheDb(acct string) {
	cd, err := cacheDir()
	if err != nil {
		w.cache = nil
		logging.Errorf("unable to find cache directory: %v", err)
		log.Errorf("unable to find cache directory: %v", err)
		return
	}
	p := path.Join(cd, acct)
	db, err := leveldb.OpenFile(p, nil)
	if err != nil {
		w.cache = nil
		logging.Errorf("failed opening cache db: %v", err)
		log.Errorf("failed opening cache db: %v", err)
		return
	}
	w.cache = db
	logging.Debugf("cache db opened: %s", p)
	log.Debugf("cache db opened: %s", p)
	if w.config.cacheMaxAge.Hours() > 0 {
		go w.cleanCache(p)
	}
@@ -54,11 +54,11 @@ func (w *IMAPWorker) initCacheDb(acct string) {
func (w *IMAPWorker) cacheHeader(mi *models.MessageInfo) {
	uv := fmt.Sprintf("%d", w.selected.UidValidity)
	uid := fmt.Sprintf("%d", mi.Uid)
	logging.Debugf("caching header for message %s.%s", uv, uid)
	log.Debugf("caching header for message %s.%s", uv, uid)
	hdr := bytes.NewBuffer(nil)
	err := textproto.WriteHeader(hdr, mi.RFC822Headers.Header.Header)
	if err != nil {
		logging.Errorf("cannot write header %s.%s: %v", uv, uid, err)
		log.Errorf("cannot write header %s.%s: %v", uv, uid, err)
		return
	}
	h := &CachedHeader{
@@ -73,18 +73,18 @@ func (w *IMAPWorker) cacheHeader(mi *models.MessageInfo) {
	enc := gob.NewEncoder(data)
	err = enc.Encode(h)
	if err != nil {
		logging.Errorf("cannot encode message %s.%s: %v", uv, uid, err)
		log.Errorf("cannot encode message %s.%s: %v", uv, uid, err)
		return
	}
	err = w.cache.Put([]byte("header."+uv+"."+uid), data.Bytes(), nil)
	if err != nil {
		logging.Errorf("cannot write header for message %s.%s: %v", uv, uid, err)
		log.Errorf("cannot write header for message %s.%s: %v", uv, uid, err)
		return
	}
}

func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
	logging.Tracef("Retrieving headers from cache: %v", msg.Uids)
	log.Tracef("Retrieving headers from cache: %v", msg.Uids)
	var need []uint32
	uv := fmt.Sprintf("%d", w.selected.UidValidity)
	for _, uid := range msg.Uids {
@@ -98,14 +98,14 @@ func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
		dec := gob.NewDecoder(bytes.NewReader(data))
		err = dec.Decode(ch)
		if err != nil {
			logging.Errorf("cannot decode cached header %s.%s: %v", uv, u, err)
			log.Errorf("cannot decode cached header %s.%s: %v", uv, u, err)
			need = append(need, uid)
			continue
		}
		hr := bytes.NewReader(ch.Header)
		textprotoHeader, err := textproto.ReadHeader(bufio.NewReader(hr))
		if err != nil {
			logging.Errorf("cannot read cached header %s.%s: %v", uv, u, err)
			log.Errorf("cannot read cached header %s.%s: %v", uv, u, err)
			need = append(need, uid)
			continue
		}
@@ -122,7 +122,7 @@ func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
		if err != nil {
			mi.Refs = refs
		}
		logging.Tracef("located cached header %s.%s", uv, u)
		log.Tracef("located cached header %s.%s", uv, u)
		w.worker.PostMessage(&types.MessageInfo{
			Message:    types.RespondTo(msg),
			Info:       mi,
@@ -154,14 +154,14 @@ func (w *IMAPWorker) cleanCache(path string) {
		dec := gob.NewDecoder(bytes.NewReader(data))
		err := dec.Decode(ch)
		if err != nil {
			logging.Errorf("cannot clean database %d: %v", w.selected.UidValidity, err)
			log.Errorf("cannot clean database %d: %v", w.selected.UidValidity, err)
			continue
		}
		exp := ch.Created.Add(w.config.cacheMaxAge)
		if exp.Before(time.Now()) {
			err = w.cache.Delete(iter.Key(), nil)
			if err != nil {
				logging.Errorf("cannot clean database %d: %v", w.selected.UidValidity, err)
				log.Errorf("cannot clean database %d: %v", w.selected.UidValidity, err)
				continue
			}
			removed++
@@ -170,6 +170,6 @@ func (w *IMAPWorker) cleanCache(path string) {
	}
	iter.Release()
	elapsed := time.Since(start)
	logging.Debugf("%s: removed %d/%d expired entries in %s",
	log.Debugf("%s: removed %d/%d expired entries in %s",
		path, removed, scanned, elapsed)
}
diff --git a/worker/imap/checkmail.go b/worker/imap/checkmail.go
index 0f347e099f49..34cf63d12e4e 100644
--- a/worker/imap/checkmail.go
+++ b/worker/imap/checkmail.go
@@ -1,7 +1,7 @@
package imap

import (
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
	"github.com/emersion/go-imap"
@@ -20,7 +20,7 @@ func (w *IMAPWorker) handleCheckMailMessage(msg *types.CheckMail) {
			continue
		}

		logging.Tracef("Getting status of directory %s", dir)
		log.Tracef("Getting status of directory %s", dir)
		status, err := w.client.Status(dir, items)
		if err != nil {
			w.worker.PostMessage(&types.Error{
diff --git a/worker/imap/connect.go b/worker/imap/connect.go
index 035feaba4b90..d6c946dbb307 100644
--- a/worker/imap/connect.go
+++ b/worker/imap/connect.go
@@ -7,7 +7,7 @@ import (
	"time"

	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/client"
)
@@ -66,7 +66,7 @@ func (w *IMAPWorker) connect() (*client.Client, error) {
		return nil, fmt.Errorf("Unknown IMAP scheme %s", w.config.scheme)
	}

	c.ErrorLog = logging.ErrorLogger()
	c.ErrorLog = log.ErrorLogger()

	if w.config.user != nil {
		username := w.config.user.Username()
@@ -165,12 +165,12 @@ func (w *IMAPWorker) setKeepaliveParameters(conn *net.TCPConn) error {
		// Max number of probes before failure
		err := lib.SetTcpKeepaliveProbes(fd, w.config.keepalive_probes)
		if err != nil {
			logging.Errorf("cannot set tcp keepalive probes: %v", err)
			log.Errorf("cannot set tcp keepalive probes: %v", err)
		}
		// Wait time after an unsuccessful probe
		err = lib.SetTcpKeepaliveInterval(fd, w.config.keepalive_interval)
		if err != nil {
			logging.Errorf("cannot set tcp keepalive interval: %v", err)
			log.Errorf("cannot set tcp keepalive interval: %v", err)
		}
	})
	return err
diff --git a/worker/imap/fetch.go b/worker/imap/fetch.go
index 9256c6ebdb9b..62451308af99 100644
--- a/worker/imap/fetch.go
+++ b/worker/imap/fetch.go
@@ -10,7 +10,7 @@ import (
	"github.com/emersion/go-message/mail"
	"github.com/emersion/go-message/textproto"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -27,7 +27,7 @@ func (imapw *IMAPWorker) handleFetchMessageHeaders(
			nil)
		return
	}
	logging.Tracef("Fetching message headers: %v", toFetch)
	log.Tracef("Fetching message headers: %v", toFetch)
	section := &imap.BodySectionName{
		BodyPartName: imap.BodyPartName{
			Specifier: imap.HeaderSpecifier,
@@ -84,7 +84,7 @@ func (imapw *IMAPWorker) handleFetchMessageHeaders(
func (imapw *IMAPWorker) handleFetchMessageBodyPart(
	msg *types.FetchMessageBodyPart,
) {
	logging.Tracef("Fetching message %d part: %v", msg.Uid, msg.Part)
	log.Tracef("Fetching message %d part: %v", msg.Uid, msg.Part)

	var partHeaderSection imap.BodySectionName
	partHeaderSection.Peek = true
@@ -130,7 +130,7 @@ func (imapw *IMAPWorker) handleFetchMessageBodyPart(
			part, err := message.New(message.Header{Header: h},
				_msg.GetBody(&partBodySection))
			if message.IsUnknownCharset(err) {
				logging.Warnf("unknown charset encountered "+
				log.Warnf("unknown charset encountered "+
					"for uid %d", _msg.Uid)
			} else if err != nil {
				return fmt.Errorf("failed to create message reader: %w", err)
@@ -158,7 +158,7 @@ func (imapw *IMAPWorker) handleFetchMessageBodyPart(
func (imapw *IMAPWorker) handleFetchFullMessages(
	msg *types.FetchFullMessages,
) {
	logging.Tracef("Fetching full messages: %v", msg.Uids)
	log.Tracef("Fetching full messages: %v", msg.Uids)
	section := &imap.BodySectionName{
		Peek: true,
	}
@@ -223,7 +223,7 @@ func (imapw *IMAPWorker) handleFetchMessages(
	done := make(chan error)

	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		var reterr error
		for _msg := range messages {
diff --git a/worker/imap/flags.go b/worker/imap/flags.go
index 7ff6de37dac8..9d9ecc86abc3 100644
--- a/worker/imap/flags.go
+++ b/worker/imap/flags.go
@@ -3,7 +3,7 @@ package imap
import (
	"github.com/emersion/go-imap"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -76,7 +76,7 @@ func (imapw *IMAPWorker) handleStoreOps(
	done := make(chan error)

	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		var reterr error
		for _msg := range messages {
diff --git a/worker/imap/idler.go b/worker/imap/idler.go
index da018334f2c8..d099ee88bef9 100644
--- a/worker/imap/idler.go
+++ b/worker/imap/idler.go
@@ -5,7 +5,7 @@ import (
	"sync"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/worker/types"
	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/client"
@@ -78,7 +78,7 @@ func (i *idler) Start() {
		i.stop = make(chan struct{})

		go func() {
			defer logging.PanicHandler()
			defer log.PanicHandler()
			select {
			case <-i.stop:
				// debounce idle
@@ -146,7 +146,7 @@ func (i *idler) waitOnIdle() {
	i.setWaiting(true)
	i.log("wait for idle in background")
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()
		err := <-i.done
		if err == nil {
			i.log("<=(idle) waited")
@@ -166,5 +166,5 @@ func (i *idler) waitOnIdle() {

func (i *idler) log(format string, v ...interface{}) {
	msg := fmt.Sprintf(format, v...)
	logging.Tracef("idler (%p) [idle:%t,wait:%t] %s", i, i.isIdleing(), i.isWaiting(), msg)
	log.Tracef("idler (%p) [idle:%t,wait:%t] %s", i, i.isIdleing(), i.isWaiting(), msg)
}
diff --git a/worker/imap/list.go b/worker/imap/list.go
index c3211f2138c5..e02d7cbbddd7 100644
--- a/worker/imap/list.go
+++ b/worker/imap/list.go
@@ -3,18 +3,18 @@ package imap
import (
	"github.com/emersion/go-imap"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
)

func (imapw *IMAPWorker) handleListDirectories(msg *types.ListDirectories) {
	mailboxes := make(chan *imap.MailboxInfo)
	logging.Tracef("Listing mailboxes")
	log.Tracef("Listing mailboxes")
	done := make(chan interface{})

	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		for mbox := range mailboxes {
			if !canOpen(mbox) {
@@ -62,7 +62,7 @@ func (imapw *IMAPWorker) handleSearchDirectory(msg *types.SearchDirectory) {
		}, nil)
	}

	logging.Tracef("Executing search")
	log.Tracef("Executing search")
	criteria, err := parseSearch(msg.Argv)
	if err != nil {
		emitError(err)
diff --git a/worker/imap/observer.go b/worker/imap/observer.go
index 867b57d9aa3a..2cfe8bd924b7 100644
--- a/worker/imap/observer.go
+++ b/worker/imap/observer.go
@@ -6,7 +6,7 @@ import (
	"sync"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/worker/types"
	"github.com/emersion/go-imap"
)
@@ -150,5 +150,5 @@ func (o *observer) emit(errMsg string) {

func (o *observer) log(format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	logging.Tracef("observer (%p) [running:%t] %s", o, o.running, msg)
	log.Tracef("observer (%p) [running:%t] %s", o, o.running, msg)
}
diff --git a/worker/imap/open.go b/worker/imap/open.go
index f554d5247fa8..ced307be4026 100644
--- a/worker/imap/open.go
+++ b/worker/imap/open.go
@@ -5,12 +5,12 @@ import (

	sortthread "github.com/emersion/go-imap-sortthread"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/worker/types"
)

func (imapw *IMAPWorker) handleOpenDirectory(msg *types.OpenDirectory) {
	logging.Debugf("Opening %s", msg.Directory)
	log.Debugf("Opening %s", msg.Directory)

	sel, err := imapw.client.Select(msg.Directory, false)
	if err != nil {
@@ -27,7 +27,7 @@ func (imapw *IMAPWorker) handleOpenDirectory(msg *types.OpenDirectory) {
func (imapw *IMAPWorker) handleFetchDirectoryContents(
	msg *types.FetchDirectoryContents,
) {
	logging.Tracef("Fetching UID list")
	log.Tracef("Fetching UID list")

	searchCriteria, err := parseSearch(msg.FilterCriteria)
	if err != nil {
@@ -52,9 +52,9 @@ func (imapw *IMAPWorker) handleFetchDirectoryContents(
	} else {
		if err != nil {
			// Non fatal, but we do want to print to get some debug info
			logging.Errorf("can't check for SORT support: %v", err)
			log.Errorf("can't check for SORT support: %v", err)
		} else if len(sortCriteria) > 0 {
			logging.Warnf("SORT is not supported but requested: list messages by UID")
			log.Warnf("SORT is not supported but requested: list messages by UID")
		}
		uids, err = imapw.client.UidSearch(searchCriteria)
	}
@@ -64,7 +64,7 @@ func (imapw *IMAPWorker) handleFetchDirectoryContents(
			Error:   err,
		}, nil)
	} else {
		logging.Tracef("Found %d UIDs", len(uids))
		log.Tracef("Found %d UIDs", len(uids))
		if len(msg.FilterCriteria) == 1 {
			// Only initialize if we are not filtering
			imapw.seqMap.Initialize(uids)
@@ -105,7 +105,7 @@ func translateSortCriterions(
func (imapw *IMAPWorker) handleDirectoryThreaded(
	msg *types.FetchDirectoryThreaded,
) {
	logging.Tracef("Fetching threaded UID list")
	log.Tracef("Fetching threaded UID list")

	searchCriteria, err := parseSearch(msg.FilterCriteria)
	if err != nil {
@@ -125,7 +125,7 @@ func (imapw *IMAPWorker) handleDirectoryThreaded(
	} else {
		aercThreads, count := convertThreads(threads, nil)
		sort.Sort(types.ByUID(aercThreads))
		logging.Tracef("Found %d threaded messages", count)
		log.Tracef("Found %d threaded messages", count)
		if len(msg.FilterCriteria) == 1 {
			// Only initialize if we are not filtering
			var uids []uint32
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index c3021f91caf2..32e05859171c 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -12,7 +12,7 @@ import (
	"github.com/syndtr/goleveldb/leveldb"

	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/handlers"
	"git.sr.ht/~rjarry/aerc/worker/types"
@@ -93,14 +93,14 @@ func (w *IMAPWorker) newClient(c *client.Client) {
	sort, err := w.client.sort.SupportSort()
	if err == nil && sort {
		w.caps.Sort = true
		logging.Debugf("Server Capability found: Sort")
		log.Debugf("Server Capability found: Sort")
	}
	for _, alg := range []sortthread.ThreadAlgorithm{sortthread.References, sortthread.OrderedSubject} {
		ok, err := w.client.Support(fmt.Sprintf("THREAD=%s", string(alg)))
		if err == nil && ok {
			w.threadAlgorithm = alg
			w.caps.Thread = true
			logging.Debugf("Server Capability found: Thread (algorithm: %s)", string(alg))
			log.Debugf("Server Capability found: Thread (algorithm: %s)", string(alg))
			break
		}
	}
@@ -233,7 +233,7 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
}

func (w *IMAPWorker) handleImapUpdate(update client.Update) {
	logging.Tracef("(= %T", update)
	log.Tracef("(= %T", update)
	switch update := update.(type) {
	case *client.MailboxUpdate:
		status := update.Mailbox
@@ -256,7 +256,7 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
		msg := update.Message
		if msg.Uid == 0 {
			if uid, found := w.seqMap.Get(msg.SeqNum); !found {
				logging.Errorf("MessageUpdate unknown seqnum: %d", msg.SeqNum)
				log.Errorf("MessageUpdate unknown seqnum: %d", msg.SeqNum)
				return
			} else {
				msg.Uid = uid
@@ -276,7 +276,7 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
		}, nil)
	case *client.ExpungeUpdate:
		if uid, found := w.seqMap.Pop(update.SeqNum); !found {
			logging.Errorf("ExpungeUpdate unknown seqnum: %d", update.SeqNum)
			log.Errorf("ExpungeUpdate unknown seqnum: %d", update.SeqNum)
		} else {
			w.worker.PostMessage(&types.MessagesDeleted{
				Uids: []uint32{uid},
diff --git a/worker/lib/parse.go b/worker/lib/parse.go
index 8c1be2a9331e..67955c8f0e30 100644
--- a/worker/lib/parse.go
+++ b/worker/lib/parse.go
@@ -10,7 +10,7 @@ import (
	"strings"
	"time"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"github.com/emersion/go-message"
	_ "github.com/emersion/go-message/charset"
@@ -384,7 +384,7 @@ func NewCRLFReader(r io.Reader) io.Reader {
func ReadMessage(r io.Reader) (*message.Entity, error) {
	entity, err := message.Read(r)
	if message.IsUnknownCharset(err) {
		logging.Warnf("unknown charset encountered")
		log.Warnf("unknown charset encountered")
	} else if err != nil {
		return nil, fmt.Errorf("could not read message: %w", err)
	}
diff --git a/worker/maildir/search.go b/worker/maildir/search.go
index 0f3f6a429787..3a78937d52eb 100644
--- a/worker/maildir/search.go
+++ b/worker/maildir/search.go
@@ -13,7 +13,7 @@ import (
	"git.sr.ht/~sircmpwn/getopt"

	"git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
)

@@ -91,7 +91,7 @@ func getParsedFlag(name string) maildir.Flag {

func (w *Worker) search(criteria *searchCriteria) ([]uint32, error) {
	requiredParts := getRequiredParts(criteria)
	logging.Debugf("Required parts bitmask for search: %b", requiredParts)
	log.Debugf("Required parts bitmask for search: %b", requiredParts)

	keys, err := w.c.UIDs(*w.selected)
	if err != nil {
@@ -112,7 +112,7 @@ func (w *Worker) search(criteria *searchCriteria) ([]uint32, error) {
			success, err := w.searchKey(key, criteria, requiredParts)
			if err != nil {
				// don't return early so that we can still get some results
				logging.Errorf("Failed to search key %d: %v", key, err)
				log.Errorf("Failed to search key %d: %v", key, err)
			} else if success {
				mu.Lock()
				matchedUids = append(matchedUids, key)
diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go
index 2a8a49bd5ce4..45eca1d4dca9 100644
--- a/worker/maildir/worker.go
+++ b/worker/maildir/worker.go
@@ -20,7 +20,7 @@ import (

	aercLib "git.sr.ht/~rjarry/aerc/lib"
	"git.sr.ht/~rjarry/aerc/lib/iterator"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/handlers"
	"git.sr.ht/~rjarry/aerc/worker/lib"
@@ -115,7 +115,7 @@ func (w *Worker) handleFSEvent(ev fsnotify.Event) {
	}
	err := w.c.SyncNewMail(*w.selected)
	if err != nil {
		logging.Errorf("could not move new to cur : %v", err)
		log.Errorf("could not move new to cur : %v", err)
		return
	}

@@ -194,18 +194,18 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
		for _, v := range files {
			key, flags, err := splitMaildirFile(v)
			if err != nil {
				logging.Errorf("%q: error parsing flags (%q): %v", v, key, err)
				log.Errorf("%q: error parsing flags (%q): %v", v, key, err)
				continue
			}
			keyFlags[key] = flags
		}
	} else {
		logging.Tracef("disabled flags cache: %q: %v", dir, err)
		log.Tracef("disabled flags cache: %q: %v", dir, err)
	}

	uids, err := w.c.UIDs(dir)
	if err != nil {
		logging.Errorf("could not get uids: %v", err)
		log.Errorf("could not get uids: %v", err)
		return dirInfo
	}

@@ -213,7 +213,7 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
	for _, uid := range uids {
		message, err := w.c.Message(dir, uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			continue
		}
		var flags []maildir.Flag
@@ -221,18 +221,18 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
			ok := false
			flags, ok = keyFlags[message.key]
			if !ok {
				logging.Tracef("message (key=%q uid=%d) not found in map cache",
				log.Tracef("message (key=%q uid=%d) not found in map cache",
					message.key, message.uid)
				flags, err = message.Flags()
				if err != nil {
					logging.Errorf("could not get flags: %v", err)
					log.Errorf("could not get flags: %v", err)
					continue
				}
			}
		} else {
			flags, err = message.Flags()
			if err != nil {
				logging.Errorf("could not get flags: %v", err)
				log.Errorf("could not get flags: %v", err)
				continue
			}
		}
@@ -301,7 +301,7 @@ func (w *Worker) handleMessage(msg types.WorkerMessage) error {
func (w *Worker) handleConfigure(msg *types.Configure) error {
	u, err := url.Parse(msg.Config.Source)
	if err != nil {
		logging.Errorf("error configuring maildir worker: %v", err)
		log.Errorf("error configuring maildir worker: %v", err)
		return err
	}
	dir := u.Path
@@ -317,11 +317,11 @@ func (w *Worker) handleConfigure(msg *types.Configure) error {
	}
	c, err := NewContainer(dir, w.maildirpp)
	if err != nil {
		logging.Errorf("could not configure maildir: %s", dir)
		log.Errorf("could not configure maildir: %s", dir)
		return err
	}
	w.c = c
	logging.Debugf("configured base maildir: %s", dir)
	log.Debugf("configured base maildir: %s", dir)
	return nil
}

@@ -338,7 +338,7 @@ func (w *Worker) handleListDirectories(msg *types.ListDirectories) error {
	}
	dirs, err := w.c.Store.FolderMap()
	if err != nil {
		logging.Errorf("failed listing directories: %v", err)
		log.Errorf("failed listing directories: %v", err)
		return err
	}
	for name := range dirs {
@@ -358,7 +358,7 @@ func (w *Worker) handleListDirectories(msg *types.ListDirectories) error {
}

func (w *Worker) handleOpenDirectory(msg *types.OpenDirectory) error {
	logging.Debugf("opening %s", msg.Directory)
	log.Debugf("opening %s", msg.Directory)

	// open the directory
	dir, err := w.c.OpenDirectory(msg.Directory)
@@ -422,13 +422,13 @@ func (w *Worker) handleFetchDirectoryContents(
	} else {
		uids, err = w.c.UIDs(*w.selected)
		if err != nil {
			logging.Errorf("failed scanning uids: %v", err)
			log.Errorf("failed scanning uids: %v", err)
			return err
		}
	}
	sortedUids, err := w.sort(uids, msg.SortCriteria)
	if err != nil {
		logging.Errorf("failed sorting directory: %v", err)
		log.Errorf("failed sorting directory: %v", err)
		return err
	}
	w.currentSortCriteria = msg.SortCriteria
@@ -461,7 +461,7 @@ func (w *Worker) sort(uids []uint32, criteria []*types.SortCriterion) ([]uint32,
			defer wg.Done()
			info, err := w.msgHeadersFromUid(uid)
			if err != nil {
				logging.Errorf("could not get message info: %v", err)
				log.Errorf("could not get message info: %v", err)
				<-limit
				return
			}
@@ -475,7 +475,7 @@ func (w *Worker) sort(uids []uint32, criteria []*types.SortCriterion) ([]uint32,
	wg.Wait()
	sortedUids, err := lib.Sort(msgInfos, criteria)
	if err != nil {
		logging.Errorf("could not sort the messages: %v", err)
		log.Errorf("could not sort the messages: %v", err)
		return nil, err
	}
	return sortedUids, nil
@@ -500,13 +500,13 @@ func (w *Worker) handleFetchDirectoryThreaded(
	} else {
		uids, err = w.c.UIDs(*w.selected)
		if err != nil {
			logging.Errorf("failed scanning uids: %v", err)
			log.Errorf("failed scanning uids: %v", err)
			return err
		}
	}
	threads, err := w.threads(uids, msg.SortCriteria)
	if err != nil {
		logging.Errorf("failed sorting directory: %v", err)
		log.Errorf("failed sorting directory: %v", err)
		return err
	}
	w.currentSortCriteria = msg.SortCriteria
@@ -531,7 +531,7 @@ func (w *Worker) threads(uids []uint32, criteria []*types.SortCriterion) ([]*typ
			defer wg.Done()
			info, err := w.msgHeadersFromUid(uid)
			if err != nil {
				logging.Errorf("could not get message info: %v", err)
				log.Errorf("could not get message info: %v", err)
				<-limit
				return
			}
@@ -552,7 +552,7 @@ func (w *Worker) threads(uids []uint32, criteria []*types.SortCriterion) ([]*typ
	default:
		uids, err = lib.Sort(msgInfos, criteria)
		if err != nil {
			logging.Errorf("could not sort the messages: %v", err)
			log.Errorf("could not sort the messages: %v", err)
			return nil, err
		}
	}
@@ -563,7 +563,7 @@ func (w *Worker) threads(uids []uint32, criteria []*types.SortCriterion) ([]*typ
func (w *Worker) handleCreateDirectory(msg *types.CreateDirectory) error {
	dir := w.c.Store.Dir(msg.Directory)
	if err := dir.Init(); err != nil {
		logging.Errorf("could not create directory %s: %v",
		log.Errorf("could not create directory %s: %v",
			msg.Directory, err)
		return err
	}
@@ -573,7 +573,7 @@ func (w *Worker) handleCreateDirectory(msg *types.CreateDirectory) error {
func (w *Worker) handleRemoveDirectory(msg *types.RemoveDirectory) error {
	dir := w.c.Store.Dir(msg.Directory)
	if err := os.RemoveAll(string(dir)); err != nil {
		logging.Errorf("could not remove directory %s: %v",
		log.Errorf("could not remove directory %s: %v",
			msg.Directory, err)
		return err
	}
@@ -586,7 +586,7 @@ func (w *Worker) handleFetchMessageHeaders(
	for _, uid := range msg.Uids {
		info, err := w.msgInfoFromUid(uid)
		if err != nil {
			logging.Errorf("could not get message info: %v", err)
			log.Errorf("could not get message info: %v", err)
			w.worker.PostMessageInfoError(msg, uid, err)
			continue
		}
@@ -605,12 +605,12 @@ func (w *Worker) handleFetchMessageBodyPart(
	// get reader
	m, err := w.c.Message(*w.selected, msg.Uid)
	if err != nil {
		logging.Errorf("could not get message %d: %v", msg.Uid, err)
		log.Errorf("could not get message %d: %v", msg.Uid, err)
		return err
	}
	r, err := m.NewBodyPartReader(msg.Part)
	if err != nil {
		logging.Errorf(
		log.Errorf(
			"could not get body part reader for message=%d, parts=%#v: %w",
			msg.Uid, msg.Part, err)
		return err
@@ -630,12 +630,12 @@ func (w *Worker) handleFetchFullMessages(msg *types.FetchFullMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.c.Message(*w.selected, uid)
		if err != nil {
			logging.Errorf("could not get message %d: %v", uid, err)
			log.Errorf("could not get message %d: %v", uid, err)
			return err
		}
		r, err := m.NewReader()
		if err != nil {
			logging.Errorf("could not get message reader: %v", err)
			log.Errorf("could not get message reader: %v", err)
			return err
		}
		defer r.Close()
@@ -666,7 +666,7 @@ func (w *Worker) handleDeleteMessages(msg *types.DeleteMessages) error {
		}, nil)
	}
	if err != nil {
		logging.Errorf("failed removing messages: %v", err)
		log.Errorf("failed removing messages: %v", err)
		return err
	}
	return nil
@@ -676,18 +676,18 @@ func (w *Worker) handleAnsweredMessages(msg *types.AnsweredMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.c.Message(*w.selected, uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			w.err(msg, err)
			continue
		}
		if err := m.MarkReplied(msg.Answered); err != nil {
			logging.Errorf("could not mark message as answered: %v", err)
			log.Errorf("could not mark message as answered: %v", err)
			w.err(msg, err)
			continue
		}
		info, err := m.MessageInfo()
		if err != nil {
			logging.Errorf("could not get message info: %v", err)
			log.Errorf("could not get message info: %v", err)
			w.err(msg, err)
			continue
		}
@@ -708,19 +708,19 @@ func (w *Worker) handleFlagMessages(msg *types.FlagMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.c.Message(*w.selected, uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			w.err(msg, err)
			continue
		}
		flag := lib.FlagToMaildir[msg.Flag]
		if err := m.SetOneFlag(flag, msg.Enable); err != nil {
			logging.Errorf("could change flag %v to %v on message: %v", flag, msg.Enable, err)
			log.Errorf("could change flag %v to %v on message: %v", flag, msg.Enable, err)
			w.err(msg, err)
			continue
		}
		info, err := m.MessageInfo()
		if err != nil {
			logging.Errorf("could not get message info: %v", err)
			log.Errorf("could not get message info: %v", err)
			w.err(msg, err)
			continue
		}
@@ -786,12 +786,12 @@ func (w *Worker) handleAppendMessage(msg *types.AppendMessage) error {
}

func (w *Worker) handleSearchDirectory(msg *types.SearchDirectory) error {
	logging.Debugf("Searching directory %v with args: %v", *w.selected, msg.Argv)
	log.Debugf("Searching directory %v with args: %v", *w.selected, msg.Argv)
	criteria, err := parseSearch(msg.Argv)
	if err != nil {
		return err
	}
	logging.Tracef("Searching with parsed criteria: %#v", criteria)
	log.Tracef("Searching with parsed criteria: %#v", criteria)
	uids, err := w.search(criteria)
	if err != nil {
		return err
diff --git a/worker/mbox/worker.go b/worker/mbox/worker.go
index 19a4497f4cd8..fcf1917dd076 100644
--- a/worker/mbox/worker.go
+++ b/worker/mbox/worker.go
@@ -10,7 +10,7 @@ import (
	"path/filepath"
	"sort"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/handlers"
	"git.sr.ht/~rjarry/aerc/worker/lib"
@@ -69,7 +69,7 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
			reterr = err
			break
		} else {
			logging.Debugf("configured with mbox file %s", dir)
			log.Debugf("configured with mbox file %s", dir)
		}

	case *types.Connect, *types.Reconnect, *types.Disconnect:
@@ -106,7 +106,7 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
			Info: w.data.DirectoryInfo(msg.Directory),
		}, nil)
		w.worker.PostMessage(&types.Done{Message: types.RespondTo(msg)}, nil)
		logging.Debugf("%s opened", msg.Directory)
		log.Debugf("%s opened", msg.Directory)

	case *types.FetchDirectoryContents:
		uids, err := filterUids(w.folder, w.folder.Uids(), msg.FilterCriteria)
@@ -167,7 +167,7 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
	case *types.FetchMessageBodyPart:
		m, err := w.folder.Message(msg.Uid)
		if err != nil {
			logging.Errorf("could not get message %d: %v", msg.Uid, err)
			log.Errorf("could not get message %d: %v", msg.Uid, err)
			reterr = err
			break
		}
@@ -186,7 +186,7 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {

		r, err := lib.FetchEntityPartReader(fullMsg, msg.Part)
		if err != nil {
			logging.Errorf(
			log.Errorf(
				"could not get body part reader for message=%d, parts=%#v: %w",
				msg.Uid, msg.Part, err)
			reterr = err
@@ -205,18 +205,18 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
		for _, uid := range msg.Uids {
			m, err := w.folder.Message(uid)
			if err != nil {
				logging.Errorf("could not get message for uid %d: %v", uid, err)
				log.Errorf("could not get message for uid %d: %v", uid, err)
				continue
			}
			r, err := m.NewReader()
			if err != nil {
				logging.Errorf("could not get message reader: %v", err)
				log.Errorf("could not get message reader: %v", err)
				continue
			}
			defer r.Close()
			b, err := io.ReadAll(r)
			if err != nil {
				logging.Errorf("could not get message reader: %v", err)
				log.Errorf("could not get message reader: %v", err)
				continue
			}
			w.worker.PostMessage(&types.FullMessage{
@@ -251,16 +251,16 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
		for _, uid := range msg.Uids {
			m, err := w.folder.Message(uid)
			if err != nil {
				logging.Errorf("could not get message: %v", err)
				log.Errorf("could not get message: %v", err)
				continue
			}
			if err := m.(*message).SetFlag(msg.Flag, msg.Enable); err != nil {
				logging.Errorf("could change flag %v to %t on message: %v", msg.Flag, msg.Enable, err)
				log.Errorf("could change flag %v to %t on message: %v", msg.Flag, msg.Enable, err)
				continue
			}
			info, err := lib.MessageInfo(m)
			if err != nil {
				logging.Errorf("could not get message info: %v", err)
				log.Errorf("could not get message info: %v", err)
				continue
			}

@@ -377,12 +377,12 @@ func filterUids(folder *container, uids []uint32, args []string) ([]uint32, erro
	if err != nil {
		return nil, err
	}
	logging.Debugf("Search with parsed criteria: %#v", criteria)
	log.Debugf("Search with parsed criteria: %#v", criteria)
	m := make([]lib.RawMessage, 0, len(uids))
	for _, uid := range uids {
		msg, err := folder.Message(uid)
		if err != nil {
			logging.Errorf("failed to get message for uid: %d", uid)
			log.Errorf("failed to get message for uid: %d", uid)
			continue
		}
		m = append(m, msg)
@@ -397,12 +397,12 @@ func sortUids(folder *container, uids []uint32,
	for _, uid := range uids {
		m, err := folder.Message(uid)
		if err != nil {
			logging.Errorf("could not get message %v", err)
			log.Errorf("could not get message %v", err)
			continue
		}
		info, err := lib.MessageInfo(m)
		if err != nil {
			logging.Errorf("could not get message info %v", err)
			log.Errorf("could not get message info %v", err)
			continue
		}
		infos = append(infos, info)
diff --git a/worker/notmuch/eventhandlers.go b/worker/notmuch/eventhandlers.go
index 388750606565..7cd9c6fc4f5b 100644
--- a/worker/notmuch/eventhandlers.go
+++ b/worker/notmuch/eventhandlers.go
@@ -7,7 +7,7 @@ import (
	"fmt"
	"strconv"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/worker/types"
)

@@ -24,7 +24,7 @@ func (w *worker) handleUpdateDirCounts(ev eventType) error {
	if w.store != nil {
		folders, err := w.store.FolderMap()
		if err != nil {
			logging.Errorf("failed listing directories: %v", err)
			log.Errorf("failed listing directories: %v", err)
			return err
		}
		for name := range folders {
diff --git a/worker/notmuch/lib/database.go b/worker/notmuch/lib/database.go
index c3c92b7f790d..79bf5be3fab8 100644
--- a/worker/notmuch/lib/database.go
+++ b/worker/notmuch/lib/database.go
@@ -9,7 +9,7 @@ import (
	"time"

	"git.sr.ht/~rjarry/aerc/lib/uidstore"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/worker/types"
	notmuch "github.com/zenhack/go.notmuch"
)
@@ -69,11 +69,11 @@ func (db *DB) withConnection(writable bool, cb func(*notmuch.DB) error) error {
	too_old := time.Now().After(db.lastOpenTime.Add(MAX_DB_AGE))
	if db.db == nil || writable || too_old {
		if cerr := db.close(); cerr != nil {
			logging.Errorf("failed to close the notmuch db: %v", cerr)
			log.Errorf("failed to close the notmuch db: %v", cerr)
		}
		err := db.connect(writable)
		if err != nil {
			logging.Errorf("failed to open the notmuch db: %v", err)
			log.Errorf("failed to open the notmuch db: %v", err)
			return err
		}
	}
@@ -81,7 +81,7 @@ func (db *DB) withConnection(writable bool, cb func(*notmuch.DB) error) error {
	if writable {
		// we need to close to commit the changes, else we block others
		if cerr := db.close(); cerr != nil {
			logging.Errorf("failed to close the notmuch db: %v", cerr)
			log.Errorf("failed to close the notmuch db: %v", cerr)
		}
	}
	return err
@@ -307,12 +307,12 @@ func (db *DB) msgModify(key string,

		err = cb(msg)
		if err != nil {
			logging.Warnf("callback failed: %v", err)
			log.Warnf("callback failed: %v", err)
		}

		err = msg.TagsToMaildirFlags()
		if err != nil {
			logging.Errorf("could not sync maildir flags: %v", err)
			log.Errorf("could not sync maildir flags: %v", err)
		}
		return nil
	})
@@ -325,13 +325,13 @@ func (db *DB) MsgModifyTags(key string, add, remove []string) error {
			for _, t := range add {
				err := msg.AddTag(t)
				if err != nil {
					logging.Warnf("failed to add tag: %v", err)
					log.Warnf("failed to add tag: %v", err)
				}
			}
			for _, t := range remove {
				err := msg.RemoveTag(t)
				if err != nil {
					logging.Warnf("failed to remove tag: %v", err)
					log.Warnf("failed to remove tag: %v", err)
				}
			}
		})
diff --git a/worker/notmuch/worker.go b/worker/notmuch/worker.go
index 5f5e403c7abe..b3022e4ca925 100644
--- a/worker/notmuch/worker.go
+++ b/worker/notmuch/worker.go
@@ -19,7 +19,7 @@ import (
	"time"

	"git.sr.ht/~rjarry/aerc/config"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/handlers"
	"git.sr.ht/~rjarry/aerc/worker/lib"
@@ -68,18 +68,18 @@ func (w *worker) Run() {
				w.w.PostMessage(&types.Unsupported{
					Message: types.RespondTo(msg),
				}, nil)
				logging.Errorf("ProcessAction(%T) unsupported: %v", msg, err)
				log.Errorf("ProcessAction(%T) unsupported: %v", msg, err)
			} else if err != nil {
				w.w.PostMessage(&types.Error{
					Message: types.RespondTo(msg),
					Error:   err,
				}, nil)
				logging.Errorf("ProcessAction(%T) failure: %v", msg, err)
				log.Errorf("ProcessAction(%T) failure: %v", msg, err)
			}
		case nmEvent := <-w.nmEvents:
			err := w.handleNotmuchEvent(nmEvent)
			if err != nil {
				logging.Errorf("notmuch event failure: %v", err)
				log.Errorf("notmuch event failure: %v", err)
			}
		}
	}
@@ -165,7 +165,7 @@ func (w *worker) handleConfigure(msg *types.Configure) error {

	u, err := url.Parse(msg.Config.Source)
	if err != nil {
		logging.Errorf("error configuring notmuch worker: %v", err)
		log.Errorf("error configuring notmuch worker: %v", err)
		return err
	}
	home, err := homedir.Expand(u.Hostname())
@@ -204,7 +204,7 @@ func (w *worker) handleConnect(msg *types.Connect) error {
	w.done(msg)
	w.emitLabelList()
	go func() {
		defer logging.PanicHandler()
		defer log.PanicHandler()

		for {
			w.nmEvents <- &updateDirCounts{}
@@ -218,7 +218,7 @@ func (w *worker) handleListDirectories(msg *types.ListDirectories) error {
	if w.store != nil {
		folders, err := w.store.FolderMap()
		if err != nil {
			logging.Errorf("failed listing directories: %v", err)
			log.Errorf("failed listing directories: %v", err)
			return err
		}
		for name := range folders {
@@ -275,7 +275,7 @@ func (w *worker) getDirectoryInfo(name string, query string) *models.DirectoryIn
}

func (w *worker) handleOpenDirectory(msg *types.OpenDirectory) error {
	logging.Tracef("opening %s", msg.Directory)
	log.Tracef("opening %s", msg.Directory)

	var isDynamicFolder bool
	q := ""
@@ -344,13 +344,13 @@ func (w *worker) handleFetchMessageHeaders(
	for _, uid := range msg.Uids {
		m, err := w.msgFromUid(uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			w.w.PostMessageInfoError(msg, uid, err)
			continue
		}
		err = w.emitMessageInfo(m, msg)
		if err != nil {
			logging.Errorf("could not emit message info: %v", err)
			log.Errorf("could not emit message info: %v", err)
			w.w.PostMessageInfoError(msg, uid, err)
			continue
		}
@@ -391,12 +391,12 @@ func (w *worker) handleFetchMessageBodyPart(
) error {
	m, err := w.msgFromUid(msg.Uid)
	if err != nil {
		logging.Errorf("could not get message %d: %v", msg.Uid, err)
		log.Errorf("could not get message %d: %v", msg.Uid, err)
		return err
	}
	r, err := m.NewBodyPartReader(msg.Part)
	if err != nil {
		logging.Errorf(
		log.Errorf(
			"could not get body part reader for message=%d, parts=%#v: %w",
			msg.Uid, msg.Part, err)
		return err
@@ -417,12 +417,12 @@ func (w *worker) handleFetchFullMessages(msg *types.FetchFullMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.msgFromUid(uid)
		if err != nil {
			logging.Errorf("could not get message %d: %v", uid, err)
			log.Errorf("could not get message %d: %v", uid, err)
			return err
		}
		r, err := m.NewReader()
		if err != nil {
			logging.Errorf("could not get message reader: %v", err)
			log.Errorf("could not get message reader: %v", err)
			return err
		}
		defer r.Close()
@@ -446,18 +446,18 @@ func (w *worker) handleAnsweredMessages(msg *types.AnsweredMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.msgFromUid(uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			w.err(msg, err)
			continue
		}
		if err := m.MarkAnswered(msg.Answered); err != nil {
			logging.Errorf("could not mark message as answered: %v", err)
			log.Errorf("could not mark message as answered: %v", err)
			w.err(msg, err)
			continue
		}
		err = w.emitMessageInfo(m, msg)
		if err != nil {
			logging.Errorf("could not emit message info: %v", err)
			log.Errorf("could not emit message info: %v", err)
			w.err(msg, err)
			continue
		}
@@ -473,18 +473,18 @@ func (w *worker) handleFlagMessages(msg *types.FlagMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.msgFromUid(uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			w.err(msg, err)
			continue
		}
		if err := m.SetFlag(msg.Flag, msg.Enable); err != nil {
			logging.Errorf("could not set flag %v as %t for message: %v", msg.Flag, msg.Enable, err)
			log.Errorf("could not set flag %v as %t for message: %v", msg.Flag, msg.Enable, err)
			w.err(msg, err)
			continue
		}
		err = w.emitMessageInfo(m, msg)
		if err != nil {
			logging.Errorf("could not emit message info: %v", err)
			log.Errorf("could not emit message info: %v", err)
			w.err(msg, err)
			continue
		}
@@ -607,7 +607,7 @@ func (w *worker) emitDirectoryContents(parent types.WorkerMessage) error {
	}
	sortedUids, err := w.sort(uids, w.currentSortCriteria)
	if err != nil {
		logging.Errorf("error sorting directory: %v", err)
		log.Errorf("error sorting directory: %v", err)
		return err
	}
	w.w.PostMessage(&types.DirectoryContents{
@@ -652,7 +652,7 @@ func (w *worker) emitMessageInfo(m *Message,
func (w *worker) emitLabelList() {
	tags, err := w.db.ListTags()
	if err != nil {
		logging.Errorf("could not load tags: %v", err)
		log.Errorf("could not load tags: %v", err)
		return
	}
	w.w.PostMessage(&types.LabelList{Labels: tags}, nil)
@@ -668,19 +668,19 @@ func (w *worker) sort(uids []uint32,
	for _, uid := range uids {
		m, err := w.msgFromUid(uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			continue
		}
		info, err := m.MessageInfo()
		if err != nil {
			logging.Errorf("could not get message info: %v", err)
			log.Errorf("could not get message info: %v", err)
			continue
		}
		msgInfos = append(msgInfos, info)
	}
	sortedUids, err := lib.Sort(msgInfos, criteria)
	if err != nil {
		logging.Errorf("could not sort the messages: %v", err)
		log.Errorf("could not sort the messages: %v", err)
		return nil, err
	}
	return sortedUids, nil
@@ -737,12 +737,12 @@ func (w *worker) handleDeleteMessages(msg *types.DeleteMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.msgFromUid(uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			w.err(msg, err)
			continue
		}
		if err := m.Remove(path); err != nil {
			logging.Errorf("could not remove message: %v", err)
			log.Errorf("could not remove message: %v", err)
			w.err(msg, err)
			continue
		}
@@ -773,11 +773,11 @@ func (w *worker) handleCopyMessages(msg *types.CopyMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.msgFromUid(uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			return err
		}
		if err := m.Copy(dest); err != nil {
			logging.Errorf("could not copy message: %v", err)
			log.Errorf("could not copy message: %v", err)
			return err
		}
	}
@@ -818,11 +818,11 @@ func (w *worker) handleMoveMessages(msg *types.MoveMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.msgFromUid(uid)
		if err != nil {
			logging.Errorf("could not get message: %v", err)
			log.Errorf("could not get message: %v", err)
			break
		}
		if err := m.Move(source, dest); err != nil {
			logging.Errorf("could not copy message: %v", err)
			log.Errorf("could not copy message: %v", err)
			break
		}
		moved = append(moved, uid)
@@ -851,7 +851,7 @@ func (w *worker) handleAppendMessage(msg *types.AppendMessage) error {
	}
	key, writer, err := dest.Create(lib.ToMaildirFlags(msg.Flags))
	if err != nil {
		logging.Errorf("could not create message at %s: %v", msg.Destination, err)
		log.Errorf("could not create message at %s: %v", msg.Destination, err)
		return err
	}
	filename, err := dest.Filename(key)
@@ -860,7 +860,7 @@ func (w *worker) handleAppendMessage(msg *types.AppendMessage) error {
		return err
	}
	if _, err := io.Copy(writer, msg.Reader); err != nil {
		logging.Errorf("could not write message to destination: %v", err)
		log.Errorf("could not write message to destination: %v", err)
		writer.Close()
		os.Remove(filename)
		return err
@@ -883,7 +883,7 @@ func (w *worker) handleCreateDirectory(msg *types.CreateDirectory) error {

	dir := w.store.Dir(msg.Directory)
	if err := dir.Init(); err != nil {
		logging.Errorf("could not create directory %s: %v",
		log.Errorf("could not create directory %s: %v",
			msg.Directory, err)
		return err
	}
@@ -898,7 +898,7 @@ func (w *worker) handleRemoveDirectory(msg *types.RemoveDirectory) error {

	dir := w.store.Dir(msg.Directory)
	if err := os.RemoveAll(string(dir)); err != nil {
		logging.Errorf("could not remove directory %s: %v",
		log.Errorf("could not remove directory %s: %v",
			msg.Directory, err)
		return err
	}
@@ -933,7 +933,7 @@ func (w *worker) processNewMaildirFiles(dir string) error {
		// Force message to move from new/ to cur/
		err = w.db.MsgModifyTags(key, nil, nil)
		if err != nil {
			logging.Errorf("MsgModifyTags failed: %v", err)
			log.Errorf("MsgModifyTags failed: %v", err)
		}
	}

diff --git a/worker/types/thread.go b/worker/types/thread.go
index bfe3edc70003..2f739bc28ed3 100644
--- a/worker/types/thread.go
+++ b/worker/types/thread.go
@@ -5,7 +5,7 @@ import (
	"fmt"
	"sort"

	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
)

type Thread struct {
@@ -80,7 +80,7 @@ func (t *Thread) Uids() []uint32 {
		return nil
	})
	if err != nil {
		logging.Errorf("walk to collect uids failed: %v", err)
		log.Errorf("walk to collect uids failed: %v", err)
	}
	return uids
}
diff --git a/worker/types/worker.go b/worker/types/worker.go
index 67cb98744295..97712afdc221 100644
--- a/worker/types/worker.go
+++ b/worker/types/worker.go
@@ -6,7 +6,7 @@ import (
	"sync/atomic"

	"git.sr.ht/~rjarry/aerc/lib/ui"
	"git.sr.ht/~rjarry/aerc/logging"
	"git.sr.ht/~rjarry/aerc/log"
	"git.sr.ht/~rjarry/aerc/models"
)

@@ -84,9 +84,9 @@ func (worker *Worker) PostAction(msg WorkerMessage, cb func(msg WorkerMessage))
	worker.setId(msg)

	if resp := msg.InResponseTo(); resp != nil {
		logging.Tracef("PostAction %T:%T", msg, resp)
		log.Tracef("PostAction %T:%T", msg, resp)
	} else {
		logging.Tracef("PostAction %T", msg)
		log.Tracef("PostAction %T", msg)
	}
	// write to Actions channel without blocking
	worker.queue(msg)
@@ -107,9 +107,9 @@ func (worker *Worker) PostMessage(msg WorkerMessage,
	msg.setAccount(worker.Name)

	if resp := msg.InResponseTo(); resp != nil {
		logging.Tracef("PostMessage %T:%T", msg, resp)
		log.Tracef("PostMessage %T:%T", msg, resp)
	} else {
		logging.Tracef("PostMessage %T", msg)
		log.Tracef("PostMessage %T", msg)
	}
	ui.MsgChannel <- msg

@@ -122,9 +122,9 @@ func (worker *Worker) PostMessage(msg WorkerMessage,

func (worker *Worker) ProcessMessage(msg WorkerMessage) WorkerMessage {
	if resp := msg.InResponseTo(); resp != nil {
		logging.Tracef("ProcessMessage %T(%d):%T(%d)", msg, msg.getId(), resp, resp.getId())
		log.Tracef("ProcessMessage %T(%d):%T(%d)", msg, msg.getId(), resp, resp.getId())
	} else {
		logging.Tracef("ProcessMessage %T(%d)", msg, msg.getId())
		log.Tracef("ProcessMessage %T(%d)", msg, msg.getId())
	}
	if inResponseTo := msg.InResponseTo(); inResponseTo != nil {
		worker.Lock()
@@ -144,9 +144,9 @@ func (worker *Worker) ProcessMessage(msg WorkerMessage) WorkerMessage {

func (worker *Worker) ProcessAction(msg WorkerMessage) WorkerMessage {
	if resp := msg.InResponseTo(); resp != nil {
		logging.Tracef("ProcessAction %T(%d):%T(%d)", msg, msg.getId(), resp, resp.getId())
		log.Tracef("ProcessAction %T(%d):%T(%d)", msg, msg.getId(), resp, resp.getId())
	} else {
		logging.Tracef("ProcessAction %T(%d)", msg, msg.getId())
		log.Tracef("ProcessAction %T(%d)", msg, msg.getId())
	}
	if inResponseTo := msg.InResponseTo(); inResponseTo != nil {
		worker.Lock()
-- 
2.38.1

Re: [PATCH aerc v2 5/5] logging: rename package to log

Details
Message ID
<COQ4A18JTLH6.NM2USZWA2NY8@spunky>
In-Reply-To
<20221127123203.145179-6-robin@jarry.cc> (view parent)
DKIM signature
pass
Download raw message
On Sun Nov 27, 2022 at 6:32 AM CST, Robin Jarry wrote:
> Use the same name than the builtin "log" package. That way, we do not
> risk logging in the wrong place.
>
> Suggested-by: Tim Culverhouse <tim@timculverhouse.com>
> Signed-off-by: Robin Jarry <robin@jarry.cc>
> ---

I can't get this to apply on master :/. I wanted to test it out but there are a
million conflicts with the rename. I am ok giving up on the rename - it's not
*that* important, just a convenience. Up to you!

--
Tim

Re: [PATCH aerc v2 5/5] logging: rename package to log

Details
Message ID
<COQT4ZU39FVN.1VPKEGO9ITSAU@paul>
In-Reply-To
<COQ4A18JTLH6.NM2USZWA2NY8@spunky> (view parent)
DKIM signature
pass
Download raw message
Tim Culverhouse, Dec 01, 2022 at 03:14:
> On Sun Nov 27, 2022 at 6:32 AM CST, Robin Jarry wrote:
> > Use the same name than the builtin "log" package. That way, we do not
> > risk logging in the wrong place.
> >
> > Suggested-by: Tim Culverhouse <tim@timculverhouse.com>
> > Signed-off-by: Robin Jarry <robin@jarry.cc>
> > ---
>
> I can't get this to apply on master :/. I wanted to test it out but there are a
> million conflicts with the rename. I am ok giving up on the rename - it's not
> *that* important, just a convenience. Up to you!

This is surprising. I have the whole series applied locally and I have
no patches before it. It is directly on top of origin/master:

0d5058822215 logging: rename package to log
c4cb8a4d75c0 logging: homogenize levels
5f5bbe56e229 logging: use local time for logging
344ba2d7097a msgviewer: add logs to display pager and filter commands
6602a1defb3e logging: add new trace log level
118ece70af51 (origin/master, origin/HEAD, github/master) colorize: add solarized theme

Re: [PATCH aerc v2 5/5] logging: rename package to log

Details
Message ID
<COQUQF8FZEN2.3SCPX4R6EAZK3@spunky>
In-Reply-To
<COQT4ZU39FVN.1VPKEGO9ITSAU@paul> (view parent)
DKIM signature
pass
Download raw message
On Thu Dec 1, 2022 at 3:43 PM CST, Robin Jarry wrote:
> Tim Culverhouse, Dec 01, 2022 at 03:14:
> > On Sun Nov 27, 2022 at 6:32 AM CST, Robin Jarry wrote:
> > > Use the same name than the builtin "log" package. That way, we do not
> > > risk logging in the wrong place.
> > >
> > > Suggested-by: Tim Culverhouse <tim@timculverhouse.com>
> > > Signed-off-by: Robin Jarry <robin@jarry.cc>
> > > ---
> >
> > I can't get this to apply on master :/. I wanted to test it out but there are a
> > million conflicts with the rename. I am ok giving up on the rename - it's not
> > *that* important, just a convenience. Up to you!
>
> This is surprising. I have the whole series applied locally and I have
> no patches before it. It is directly on top of origin/master:

Strange...I also did on plain old master and only 5/5 doesn't apply for me.
Something really weird is going on though, here is my git status after trying to
`git am`...it wants to delete widgets, worker, and logging:

On branch master
Your branch is ahead of 'prod/master' by 4 commits.
  (use "git push" to publish your local commits)

You are in the middle of an am session.
  (fix conflicts and then run "git am --continue")
  (use "git am --skip" to skip this patch)
  (use "git am --abort" to restore the original branch)

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   .gitignore
	modified:   CONTRIBUTING.md
	modified:   README.md
	modified:   aerc.go
	modified:   commands/account/compose.go
	modified:   commands/account/export-mbox.go
	modified:   commands/account/import-mbox.go
	modified:   commands/account/recover.go
	modified:   commands/account/search.go
	modified:   commands/compose/attach.go
	modified:   commands/compose/postpone.go
	modified:   commands/compose/send.go
	modified:   commands/exec.go
	modified:   commands/history.go
	modified:   commands/msg/archive.go
	modified:   commands/msg/envelope.go
	modified:   commands/msg/forward.go
	modified:   commands/msg/invite.go
	modified:   commands/msg/pipe.go
	modified:   commands/msg/recall.go
	modified:   commands/msg/reply.go
	modified:   commands/msg/unsubscribe.go
	modified:   commands/msgview/save.go
	modified:   commands/util.go
	modified:   completer/completer.go
	modified:   config/accounts.go
	modified:   config/binds.go
	modified:   config/compose.go
	modified:   config/filters.go
	modified:   config/general.go
	modified:   config/openers.go
	modified:   config/statusline.go
	modified:   config/templates.go
	modified:   config/triggers.go
	modified:   config/ui.go
	modified:   config/viewer.go
	modified:   doc/aerc.1.scd
	modified:   lib/attachment.go
	modified:   lib/crypto/gpg/gpgbin/gpgbin.go
	modified:   lib/crypto/pgp/pgp.go
	modified:   lib/messageview.go
	modified:   lib/msgstore.go
	modified:   lib/open.go
	modified:   lib/parse/ansi.go
	modified:   lib/socket.go
	modified:   lib/threadbuilder.go
	modified:   lib/ui/textinput.go
	deleted:    logging/logger.go
	deleted:    logging/panic-logger.go
	deleted:    widgets/account.go
	deleted:    widgets/aerc.go
	deleted:    widgets/compose.go
	deleted:    widgets/dirlist.go
	deleted:    widgets/dirtree.go
	deleted:    widgets/listbox.go
	deleted:    widgets/msglist.go
	deleted:    widgets/msgviewer.go
	deleted:    widgets/spinner.go
	deleted:    widgets/status.go
	deleted:    widgets/terminal.go
	deleted:    worker/imap/cache.go
	deleted:    worker/imap/checkmail.go
	deleted:    worker/imap/connect.go
	deleted:    worker/imap/fetch.go
	deleted:    worker/imap/flags.go
	deleted:    worker/imap/idler.go
	deleted:    worker/imap/list.go
	deleted:    worker/imap/observer.go
	deleted:    worker/imap/open.go
	deleted:    worker/imap/worker.go
	deleted:    worker/lib/parse.go
	deleted:    worker/maildir/search.go
	deleted:    worker/maildir/worker.go
	deleted:    worker/mbox/worker.go
	deleted:    worker/notmuch/eventhandlers.go
	deleted:    worker/notmuch/lib/database.go
	deleted:    worker/notmuch/worker.go
	deleted:    worker/types/thread.go
	deleted:    worker/types/worker.go

no changes added to commit (use "git add" and/or "git commit -a")
Reply to thread Export thread (mbox)