diff --git a/src/lib.rs b/src/lib.rs
index 1403ccd..98a48d8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -179,7 +179,8 @@ impl AndroidLogger {
 
 static ANDROID_LOGGER: OnceLock<AndroidLogger> = OnceLock::new();
 
-const LOGGING_TAG_MAX_LEN: usize = 23;
+// Maximum length of a tag that does not require allocation.
+const LOGGING_TAG_MAX_LEN: usize = 127;
 const LOGGING_MSG_MAX_LEN: usize = 4000;
 
 impl Default for AndroidLogger {
@@ -211,10 +212,10 @@ impl Log for AndroidLogger {
             return;
         }
 
-        // tag must not exceed LOGGING_TAG_MAX_LEN
+        // tag longer than LOGGING_TAG_MAX_LEN causes allocation
         let mut tag_bytes: [MaybeUninit<u8>; LOGGING_TAG_MAX_LEN + 1] = uninit_array();
 
-        let module_path = record.module_path().unwrap_or_default().to_owned();
+        let module_path = record.module_path().unwrap_or_default();
 
         // If no tag was specified, use module name
         let custom_tag = &config.tag;
@@ -223,10 +224,23 @@ impl Log for AndroidLogger {
             .map(|s| s.as_bytes())
             .unwrap_or_else(|| module_path.as_bytes());
 
-        // truncate the tag here to fit into LOGGING_TAG_MAX_LEN
-        self.fill_tag_bytes(&mut tag_bytes, tag);
-        // use stack array as C string
-        let tag: &CStr = unsafe { CStr::from_ptr(mem::transmute(tag_bytes.as_ptr())) };
+        // In case we end up allocating, keep the CString alive.
+        let _owned_tag;
+        let tag: &CStr = if tag.len() < tag_bytes.len() {
+            // use stack array as C string
+            self.fill_tag_bytes(&mut tag_bytes, tag);
+            // SAFETY: fill_tag_bytes always puts a nullbyte in tag_bytes.
+            unsafe { CStr::from_ptr(mem::transmute(tag_bytes.as_ptr())) }
+        } else {
+            // Tag longer than available stack buffer; allocate.
+            // We're using either
+            // - CString::as_bytes on config.tag, or
+            // - str::as_bytes on record.module_path()
+            // Neither of those include the terminating nullbyte.
+            _owned_tag = CString::new(tag)
+                .expect("config.tag or record.module_path() should never contain nullbytes");
+            _owned_tag.as_ref()
+        };
 
         // message must not exceed LOGGING_MSG_MAX_LEN
         // therefore split log message into multiple log calls