diff --git a/logs/logs.go b/logs/logs.go
index 42fa46c64c14bd464e7a637e1267a12bbea923ee..8be20d95f4b85dcb8c2713fb3af96f7a70efc8ab 100644
--- a/logs/logs.go
+++ b/logs/logs.go
@@ -1,6 +1,8 @@
 package logs
 
 import (
+	"bytes"
+	"encoding/json"
 	"fmt"
 	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors"
 	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/string_utils"
@@ -100,11 +102,7 @@ func InitLogs(requestID *string, isDebugBuild bool, buildVersion string, request
 		})
 	} else {
 		log.SetReportCaller(true)
-		log.SetFormatter(&log.JSONFormatter{
-			CallerPrettyfier: func(f *runtime.Frame) (string, string) {
-				// Exclude the caller, will rather be added as a field
-				return "", ""
-			}})
+		log.SetFormatter(&CustomLogFormatter{})
 	}
 	log.SetLevel(LogLevel())
 
@@ -313,3 +311,38 @@ func fakeHttpRequest() *http.Request {
 	}
 	return &request
 }
+
+type CustomLogFormatter struct {
+}
+
+func (f *CustomLogFormatter) Format(entry *log.Entry) ([]byte, error) {
+	data := map[string]any{}
+	for k, v := range entry.Data {
+		switch v := v.(type) {
+		case error:
+			// Otherwise errors are ignored by `encoding/json`
+			// https://github.com/sirupsen/logrus/issues/137
+			data[k] = v.Error()
+		default:
+			data[k] = v
+		}
+	}
+	if entry.Message != "" {
+		data["msg"] = entry.Message
+	}
+
+	var b *bytes.Buffer
+	if entry.Buffer != nil {
+		b = entry.Buffer
+	} else {
+		b = &bytes.Buffer{}
+	}
+
+	encoder := json.NewEncoder(b)
+	encoder.SetEscapeHTML(true)
+	if err := encoder.Encode(entry.Data); err != nil {
+		return nil, fmt.Errorf("failed to marshal fields to JSON, %w", err)
+	}
+
+	return b.Bytes(), nil
+}