Allow !replace
-ing service log-targets
in merge
#221
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Alternative to #223.
Context
#209 and #217 have included extensive discussion of the configuration and merging of log targets specified in a service definition. Two issues have been identified when it comes to merging the
log-targets
field:It is hard to restore the default behaviour provided when
log-targets
is not specified. The issue is that specifying a null valueparses identically to not specifying a value at all:
It is hard to remove a log target which was previously specified. If your base layer contains
and you merge the following layer on top of it:
it will yield
log-targets: [a,b,c]
.As it stands, the only way to get around either issue is to replace the entire service - which is a real usability issue. This PR proposes one solution to the problem.
The solution
To solve (1), we need an explicit value to represent the default behaviour. We can't use
null
in a merge, as when this is parsed, it is indistinguishable from an unspecified value. To this end, I have added adefault
keyword which can be specified as the value oflog-targets
to restore the default behaviour:To solve the issue raised by Gustavo here, I have also added a
none
keyword which a service can use to entirely opt-out of log forwarding. Personally I feel this is a safer approach than what I've proposed in #217. Distinguishing between[]string(nil)
and[]string{}
in Go is fiddly and error-prone, and it's bound to cause issues down the road when merging and passing structs around.Finally, I've added an
all
keyword - this is not strictly necessary, but could be convenient if a user has a large number of log targets.To solve (2), I've added a
!replace
tag, which a service can use during a merge to indicate that the value oflog-targets
should be replaced, not merged. i.e. mergingon top of another layer will overwrite the value of
log-targets
, yielding justlog-targets: [c]
.So, the full schema for the
log-targets
field is now:I've implemented a custom type
LogTargets
with a customUnmarshalYAML
method to handle all this.Merging rules
These are the rules I decided on for merging
log-targets
- see theMergeLogTargets
function. Open to discussing the details here.anything1
<-!replace anything2
yieldsanything2
. In particular, merginglist1
<-!replace list2
yieldslist2
.list1
<-list2
will combine the two lists.list
<-keyword
yieldskeyword
.keyword1
<-keyword2
yieldskeyword2
keyword
<-list
yieldslist
(if the list is nonempty).Essentially, the
!replace
directive is only needed when wanting to replace a list with another list.