Browse Source

Log modified processing options only

DarthSim 5 years ago
parent
commit
cc394501df
3 changed files with 146 additions and 17 deletions
  1. 2 1
      CHANGELOG.md
  2. 38 16
      processing_options.go
  3. 106 0
      struct-diff/diff.go

+ 2 - 1
CHANGELOG.md

@@ -7,7 +7,8 @@
 - Using Application Default Credentials when `IMGPROXY_USE_GCS` is set to `true` but `IMGPROXY_GCS_KEY` is not set.
   **Note:** If you use `IMGPROXY_GCS_KEY`, it's recommended to set `IMGPROXY_USE_GCS` to `true` since it may be required by future versions to enable GCS support;
 - Setting `IMGPROXY_REPORT_DOWNLOADING_ERRORS` to `false` disables reporting of downloading errors;
-- SVG passthrough. When source image and requested format are SVG, image will be returned without changes.
+- SVG passthrough. When source image and requested format are SVG, image will be returned without changes;
+- Log only modified processing options.
 
 ## v2.5.0
 

+ 38 - 16
processing_options.go

@@ -10,6 +10,9 @@ import (
 	"regexp"
 	"strconv"
 	"strings"
+	"sync"
+
+	structdiff "github.com/imgproxy/imgproxy/struct-diff"
 )
 
 type urlOption struct {
@@ -158,22 +161,33 @@ func (rt resizeType) String() string {
 	return ""
 }
 
+var (
+	_newProcessingOptions    processingOptions
+	newProcessingOptionsOnce sync.Once
+)
+
 func newProcessingOptions() *processingOptions {
-	return &processingOptions{
-		Resize:      resizeFit,
-		Width:       0,
-		Height:      0,
-		Gravity:     gravityOptions{Type: gravityCenter},
-		Enlarge:     false,
-		Quality:     conf.Quality,
-		Format:      imageTypeUnknown,
-		Background:  rgbColor{255, 255, 255},
-		Blur:        0,
-		Sharpen:     0,
-		Dpr:         1,
-		Watermark:   watermarkOptions{Opacity: 1, Replicate: false, Gravity: gravityCenter},
-		UsedPresets: make([]string, 0, len(conf.Presets)),
-	}
+	newProcessingOptionsOnce.Do(func() {
+		_newProcessingOptions = processingOptions{
+			Resize:     resizeFit,
+			Width:      0,
+			Height:     0,
+			Gravity:    gravityOptions{Type: gravityCenter},
+			Enlarge:    false,
+			Quality:    conf.Quality,
+			Format:     imageTypeUnknown,
+			Background: rgbColor{255, 255, 255},
+			Blur:       0,
+			Sharpen:    0,
+			Dpr:        1,
+			Watermark:  watermarkOptions{Opacity: 1, Replicate: false, Gravity: gravityCenter},
+		}
+	})
+
+	po := _newProcessingOptions
+	po.UsedPresets = make([]string, 0, len(conf.Presets))
+
+	return &po
 }
 
 func (po *processingOptions) isPresetUsed(name string) bool {
@@ -189,8 +203,16 @@ func (po *processingOptions) presetUsed(name string) {
 	po.UsedPresets = append(po.UsedPresets, name)
 }
 
+func (po *processingOptions) Diff() structdiff.Entries {
+	return structdiff.Diff(newProcessingOptions(), po)
+}
+
 func (po *processingOptions) String() string {
-	return fmt.Sprintf("%+v", *po)
+	return po.Diff().String()
+}
+
+func (po *processingOptions) MarshalJSON() ([]byte, error) {
+	return po.Diff().MarshalJSON()
 }
 
 func colorFromHex(hexcolor string) (rgbColor, error) {

+ 106 - 0
struct-diff/diff.go

@@ -0,0 +1,106 @@
+package structdiff
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"reflect"
+	"sync"
+)
+
+var bufPool = sync.Pool{
+	New: func() interface{} {
+		return new(bytes.Buffer)
+	},
+}
+
+type Entry struct {
+	Name  string
+	Value interface{}
+}
+
+type Entries []Entry
+
+func (d Entries) String() string {
+	buf := bufPool.Get().(*bytes.Buffer)
+	last := len(d) - 1
+
+	buf.Reset()
+
+	for i, e := range d {
+		buf.WriteString(e.Name)
+		buf.WriteString(": ")
+
+		if dd, ok := e.Value.(Entries); ok {
+			buf.WriteByte('{')
+			buf.WriteString(dd.String())
+			buf.WriteByte('}')
+		} else {
+			fmt.Fprint(buf, e.Value)
+		}
+
+		if i != last {
+			buf.WriteString("; ")
+		}
+	}
+
+	return buf.String()
+}
+
+func (d Entries) MarshalJSON() ([]byte, error) {
+	buf := bufPool.Get().(*bytes.Buffer)
+	last := len(d) - 1
+
+	buf.Reset()
+
+	buf.WriteByte('{')
+
+	for i, e := range d {
+		j, err := json.Marshal(e.Value)
+		if err != nil {
+			return nil, err
+		}
+
+		fmt.Fprintf(buf, "%q:%s", e.Name, j)
+
+		if i != last {
+			buf.WriteByte(',')
+		}
+	}
+
+	buf.WriteByte('}')
+
+	return buf.Bytes(), nil
+}
+
+func Diff(a, b interface{}) Entries {
+	valA := reflect.Indirect(reflect.ValueOf(a))
+	valB := reflect.Indirect(reflect.ValueOf(b))
+
+	d := make(Entries, 0, valA.NumField())
+
+	if valA.Type() != valB.Type() {
+		return d
+	}
+
+	for i := 0; i < valA.NumField(); i++ {
+		fieldA := valA.Field(i)
+		fieldB := valB.Field(i)
+
+		intA := fieldA.Interface()
+		intB := fieldB.Interface()
+
+		if !reflect.DeepEqual(intA, intB) {
+			name := valB.Type().Field(i).Name
+			value := intB
+
+			if fieldB.Kind() == reflect.Struct {
+				value = Diff(intA, intB)
+			}
+
+			d = append(d, Entry{name, value})
+		}
+	}
+
+	return d
+}