diff --git a/internal/container/event_generator.go b/internal/container/event_generator.go
index 4642612f..85b0c54f 100644
--- a/internal/container/event_generator.go
+++ b/internal/container/event_generator.go
@@ -87,7 +87,6 @@ func (g *EventGenerator) consumeReader() {
logEvent := createEvent(message, streamType)
logEvent.ContainerID = g.containerID
logEvent.Level = guessLogLevel(logEvent)
- escape(logEvent)
g.buffer <- logEvent
}
diff --git a/internal/support/search/search.go b/internal/support/search/search.go
index 8d6f9df3..e8e8a42a 100644
--- a/internal/support/search/search.go
+++ b/internal/support/search/search.go
@@ -10,6 +10,11 @@ import (
orderedmap "github.com/wk8/go-ordered-map/v2"
)
+const (
+ MarkerStart = "\uE000"
+ MarkerEnd = "\uE001"
+)
+
func ParseRegex(search string) (*regexp.Regexp, error) {
flags := ""
@@ -30,7 +35,7 @@ func Search(re *regexp.Regexp, logEvent *container.LogEvent) bool {
switch value := logEvent.Message.(type) {
case string:
if re.MatchString(value) {
- logEvent.Message = re.ReplaceAllString(value, "$0")
+ logEvent.Message = re.ReplaceAllString(value, MarkerStart+"$0"+MarkerEnd)
return true
}
@@ -56,9 +61,9 @@ func searchMapAny(re *regexp.Regexp, orderedMap *orderedmap.OrderedMap[string, a
for pair := orderedMap.Oldest(); pair != nil; pair = pair.Next() {
switch value := pair.Value.(type) {
case string:
- if re.MatchString(value) {
+ if replaced, matched := searchString(re, value); matched {
found = true
- orderedMap.Set(pair.Key, re.ReplaceAllString(value, "$0"))
+ orderedMap.Set(pair.Key, replaced)
}
case []any:
@@ -84,7 +89,7 @@ func searchMapAny(re *regexp.Regexp, orderedMap *orderedmap.OrderedMap[string, a
case int, float64, bool:
formatted := fmt.Sprintf("%v", value)
if re.MatchString(formatted) {
- orderedMap.Set(pair.Key, re.ReplaceAllString(formatted, "$0"))
+ orderedMap.Set(pair.Key, re.ReplaceAllString(formatted, MarkerStart+"$0"+MarkerEnd))
found = true
}
@@ -101,11 +106,10 @@ func searchMap(re *regexp.Regexp, data map[string]interface{}) bool {
for key, value := range data {
switch value := value.(type) {
case string:
- if re.MatchString(value) {
- data[key] = re.ReplaceAllString(value, "$0")
+ if replaced, matched := searchString(re, value); matched {
found = true
+ data[key] = replaced
}
-
case []any:
if searchArray(re, value) {
found = true
@@ -119,7 +123,7 @@ func searchMap(re *regexp.Regexp, data map[string]interface{}) bool {
case int, float64, bool:
formatted := fmt.Sprintf("%v", value)
if re.MatchString(formatted) {
- data[key] = re.ReplaceAllString(formatted, "$0")
+ data[key] = re.ReplaceAllString(formatted, MarkerStart+"$0"+MarkerEnd)
found = true
}
default:
@@ -133,9 +137,9 @@ func searchMap(re *regexp.Regexp, data map[string]interface{}) bool {
func searchMapString(re *regexp.Regexp, orderedMap *orderedmap.OrderedMap[string, string]) bool {
found := false
for pair := orderedMap.Oldest(); pair != nil; pair = pair.Next() {
- if re.MatchString(pair.Value) {
- orderedMap.Set(pair.Key, re.ReplaceAllString(pair.Value, "$0"))
+ if replaced, matched := searchString(re, pair.Value); matched {
found = true
+ orderedMap.Set(pair.Key, replaced)
}
}
return found
@@ -146,14 +150,14 @@ func searchArray(re *regexp.Regexp, data []any) bool {
for i, value := range data {
switch value := value.(type) {
case string:
- if re.MatchString(value) {
- data[i] = re.ReplaceAllString(value, "$0")
+ if replaced, matched := searchString(re, value); matched {
found = true
+ data[i] = replaced
}
case int, float64, bool:
formatted := fmt.Sprintf("%v", value)
if re.MatchString(formatted) {
- data[i] = re.ReplaceAllString(formatted, "$0")
+ data[i] = re.ReplaceAllString(formatted, MarkerStart+"$0"+MarkerEnd)
found = true
}
case []any:
@@ -169,3 +173,12 @@ func searchArray(re *regexp.Regexp, data []any) bool {
return found
}
+
+func searchString(re *regexp.Regexp, value string) (string, bool) {
+ if re.MatchString(value) {
+ replaced := re.ReplaceAllString(value, MarkerStart+"$0"+MarkerEnd)
+ return replaced, true
+ }
+
+ return value, false
+}
diff --git a/internal/container/escape.go b/internal/support/web/escape.go
similarity index 55%
rename from internal/container/escape.go
rename to internal/support/web/escape.go
index 9ddc0e68..8c843b77 100644
--- a/internal/container/escape.go
+++ b/internal/support/web/escape.go
@@ -1,16 +1,21 @@
-package container
+package support_web
import (
"html"
+ "strings"
+ "github.com/amir20/dozzle/internal/container"
+ "github.com/amir20/dozzle/internal/support/search"
"github.com/rs/zerolog/log"
orderedmap "github.com/wk8/go-ordered-map/v2"
)
-func escape(logEvent *LogEvent) {
+func EscapeHTMLValues(logEvent *container.LogEvent) {
switch value := logEvent.Message.(type) {
case string:
- logEvent.Message = html.EscapeString(value)
+ value = html.EscapeString(value)
+ value = strings.ReplaceAll(value, search.MarkerStart, "")
+ logEvent.Message = strings.ReplaceAll(value, search.MarkerEnd, "")
case *orderedmap.OrderedMap[string, any]:
escapeAnyMap(value)
@@ -33,7 +38,10 @@ func escapeAnyMap(orderedMap *orderedmap.OrderedMap[string, any]) {
for pair := orderedMap.Oldest(); pair != nil; pair = pair.Next() {
switch value := pair.Value.(type) {
case string:
- orderedMap.Set(pair.Key, html.EscapeString(value))
+ value = html.EscapeString(value)
+ value = strings.ReplaceAll(value, search.MarkerStart, "")
+ value = strings.ReplaceAll(value, search.MarkerEnd, "")
+ orderedMap.Set(pair.Key, value)
case *orderedmap.OrderedMap[string, any]:
escapeAnyMap(value)
case *orderedmap.OrderedMap[string, string]:
@@ -45,6 +53,9 @@ func escapeAnyMap(orderedMap *orderedmap.OrderedMap[string, any]) {
func escapeStringMap(orderedMap *orderedmap.OrderedMap[string, string]) {
for pair := orderedMap.Oldest(); pair != nil; pair = pair.Next() {
- orderedMap.Set(pair.Key, html.EscapeString(pair.Value))
+ value := html.EscapeString(pair.Value)
+ value = strings.ReplaceAll(value, search.MarkerStart, "")
+ value = strings.ReplaceAll(value, search.MarkerEnd, "")
+ orderedMap.Set(pair.Key, value)
}
}
diff --git a/internal/web/logs.go b/internal/web/logs.go
index bf67ad6b..d8956379 100644
--- a/internal/web/logs.go
+++ b/internal/web/logs.go
@@ -158,6 +158,7 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
break
}
+ support_web.EscapeHTMLValues(event) // only escape when not exporting
buffer.Push(event)
}
}
@@ -391,6 +392,8 @@ loop:
if _, ok := levels[logEvent.Level]; !ok {
continue
}
+
+ support_web.EscapeHTMLValues(logEvent)
sseWriter.Message(logEvent)
case c := <-newContainers:
if _, err := h.hostService.FindContainer(c.Host, c.ID, userLabels); err == nil {
@@ -405,6 +408,9 @@ loop:
}
case backfillEvents := <-backfill:
+ for _, event := range backfillEvents {
+ support_web.EscapeHTMLValues(event)
+ }
if err := sseWriter.Event("logs-backfill", backfillEvents); err != nil {
log.Error().Err(err).Msg("error encoding container event")
}