-
Notifications
You must be signed in to change notification settings - Fork 218
feat: improve diff logging #2544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e469ec1
bd0ff66
4cea98f
dcff1ba
a45f3da
c1b86b8
611ecdb
57a0ee2
962cea7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.LinkedHashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Map.Entry; | ||
|
@@ -25,6 +26,9 @@ | |
import io.javaoperatorsdk.operator.api.reconciler.Context; | ||
import io.javaoperatorsdk.operator.processing.LoggingUtils; | ||
|
||
import com.github.difflib.DiffUtils; | ||
import com.github.difflib.UnifiedDiffUtils; | ||
|
||
/** | ||
* Matches the actual state on the server vs the desired state. Based on the managedFields of SSA. | ||
* | ||
|
@@ -103,20 +107,66 @@ public boolean matches(R actual, R desired, Context<?> context) { | |
|
||
removeIrrelevantValues(desiredMap); | ||
|
||
if (LoggingUtils.isNotSensitiveResource(desired)) { | ||
logDiff(prunedActual, desiredMap, objectMapper); | ||
var matches = prunedActual.equals(desiredMap); | ||
|
||
if (!matches && log.isDebugEnabled() && LoggingUtils.isNotSensitiveResource(desired)) { | ||
var diff = getDiff(prunedActual, desiredMap, objectMapper); | ||
log.debug( | ||
"Diff between actual and desired state for resource: {} with name: {} in namespace: {} is: \n{}", | ||
actual.getKind(), actual.getMetadata().getName(), actual.getMetadata().getNamespace(), | ||
diff); | ||
} | ||
|
||
return prunedActual.equals(desiredMap); | ||
return matches; | ||
} | ||
|
||
private void logDiff(Map<String, Object> prunedActualMap, Map<String, Object> desiredMap, | ||
private String getDiff(Map<String, Object> prunedActualMap, Map<String, Object> desiredMap, | ||
KubernetesSerialization serialization) { | ||
if (log.isDebugEnabled()) { | ||
var actualYaml = serialization.asYaml(prunedActualMap); | ||
var desiredYaml = serialization.asYaml(desiredMap); | ||
log.debug("Pruned actual yaml: \n {} \n desired yaml: \n {} ", actualYaml, desiredYaml); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We still might want to log the actual resources. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when should we log actual resources? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean it is good that we log the diff, but some might be interested in the actual resources (I mean both "actual" and desired yaml). It might be useful to log that too? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
how about logging actual resource in case when logger is enabled for the trace level? or should we introduce new configuration parameter? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trace level is fine by me, we could have there both the resources. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, I enabled printing actual and desired resources when trace is enabled. |
||
var actualYaml = serialization.asYaml(sortMap(prunedActualMap)); | ||
var desiredYaml = serialization.asYaml(sortMap(desiredMap)); | ||
if (log.isTraceEnabled()) { | ||
log.trace("Pruned actual resource: \n {} \ndesired resource: \n {} ", actualYaml, | ||
desiredYaml); | ||
} | ||
|
||
var patch = DiffUtils.diff(actualYaml.lines().toList(), desiredYaml.lines().toList()); | ||
List<String> unifiedDiff = | ||
UnifiedDiffUtils.generateUnifiedDiff("", "", actualYaml.lines().toList(), patch, 1); | ||
return String.join("\n", unifiedDiff); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
Map<String, Object> sortMap(Map<String, Object> map) { | ||
List<String> sortedKeys = new ArrayList<>(map.keySet()); | ||
Collections.sort(sortedKeys); | ||
|
||
Map<String, Object> sortedMap = new LinkedHashMap<>(); | ||
for (String key : sortedKeys) { | ||
Object value = map.get(key); | ||
if (value instanceof Map) { | ||
sortedMap.put(key, sortMap((Map<String, Object>) value)); | ||
} else if (value instanceof List) { | ||
sortedMap.put(key, sortListItems((List<Object>) value)); | ||
} else { | ||
sortedMap.put(key, value); | ||
} | ||
} | ||
return sortedMap; | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
List<Object> sortListItems(List<Object> list) { | ||
List<Object> sortedList = new ArrayList<>(); | ||
for (Object item : list) { | ||
if (item instanceof Map) { | ||
sortedList.add(sortMap((Map<String, Object>) item)); | ||
} else if (item instanceof List) { | ||
sortedList.add(sortListItems((List<Object>) item)); | ||
} else { | ||
sortedList.add(item); | ||
} | ||
} | ||
return sortedList; | ||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The diff should be calculated only if debug enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right, this costs a lot.