I figured out something like this works:
<pattern>%date [%level][%logger{1}][%thread{1}]
%message%replace(%xException){"\n", "\\n"}%nopex%n</pattern>
The %replace mechanism works on a stacktrace text. You also need %nopex to prevent the raw stacktrace from showing up again; otherwise Logback "helpfully" notices you omitted the trace and includes it for you.