Skip to content
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

Feature/tags for elasticsearchwriter #10074

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

SebastianOpeni
Copy link

Offers to add additional tags to entries written by the ElasticSearchWriter.

As discussed with Eric at the icinga summit we are submitting this feature. Please revise the code and let us know if there is something we need to improve. otherwise we would be happy for timely merge.

fixes #6837

Copy link

cla-bot bot commented Jun 7, 2024

Thank you for your pull request. Before we can look at it, you'll need to sign a Contributor License Agreement (CLA).

Please follow instructions at https://icinga.com/company/contributor-agreement to sign the CLA.

After that, please reply here with a comment and we'll verify.

Contributors that have not signed yet: @SebastianOpeni

  • If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address. Please contact us if you think this is the case.

  • If you signed the CLA as a corporation, your GitHub username may not have been submitted to us. Please reach out to the responsible person in your organization.

@icinga-probot icinga-probot bot added the area/elastic Events to Elasticsearch label Jun 7, 2024
Copy link

@ngoeddel-openi ngoeddel-openi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@SebastianOpeni
Copy link
Author

The CLA should be signed now.

@bobapple
Copy link
Member

bobapple commented Jun 7, 2024

@cla-bot check

@cla-bot cla-bot bot added the cla/signed label Jun 7, 2024
Copy link
Member

@yhabteab yhabteab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for your contribution! I've just been looking over the code changes and left some inline comments below, but haven't tested it with an Elastic/OpenSearch instance yet. Other than that, can you please rebase this against the current master to fix the GitHub actions. Thanks!

@@ -63,3 +63,4 @@ Robin O'Brien <[email protected]> <[email protected]>
Roman Gerhardt <[email protected]> <[email protected]>
Sebastian Chrostek <[email protected]> <[email protected]>
Thomas Gelf <[email protected]> <[email protected]>
Sebastian Grund <[email protected]> <[email protected]>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That change is not necessary as both of your mails are the same! .mailmap is actually there to map different mails of an author.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please commit all the changes in this file separately.

Comment on lines +26 to +27
void ValidateHostTagsTemplate(const Lazy<Dictionary::Ptr> &lvalue, const ValidationUtils &utils);
void ValidateServiceTagsTemplate(const Lazy<Dictionary::Ptr> &lvalue, const ValidationUtils &utils);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are overriding virtual methods here, so please add the override keyword at the end.

Comment on lines +32 to +43
[config, required] Dictionary::Ptr host_tags_template {
default {{{
return new Dictionary({
});
}}}
};
[config, required] Dictionary::Ptr service_tags_template {
default {{{
return new Dictionary({
});
}}}
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is unclear to me what the advantage is of labelling these attributes as required and returning an empty dictionary by default. Would it not be more appropriate to omit the required keyword altogether with the default values and simply declare them as [config] Dictionary::Ptr host_tags_template;?

Btw, while these are labelled as required, you've documented them as being optional.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are absolutely right about the required keyword and I will remove it. 🙈
(To be perfectly honest I took heavy inspiration for this part from the definition of the influx perfdata writer. So most likely it has to be removed there too.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(To be perfectly honest I took heavy inspiration for this part from the definition of the influx perfdata writer. So most likely it has to be removed there too.)

The InfluxDB Writer doesn't return an empty dictionary by default, instead it requires that the two dictionary keys measurement and tags to be always there, i.e. the attribute host_template is never allowed to be empty. Here on the other hand, there are no really meaningful default values, so it should not be marked as required and the empty default value should be removed as well.

Comment on lines +32 to +43
[config, required] Dictionary::Ptr host_tags_template {
default {{{
return new Dictionary({
});
}}}
};
[config, required] Dictionary::Ptr service_tags_template {
default {{{
return new Dictionary({
});
}}}
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are nested dictionaries/arrays supported or only simple key-value pairs? If not, it would be advisable to add such a validator for these two new attributes, otherwise, Icinga 2 will simply fail without any indication of that misconfigured type, e.g. when using such a config: host_tags_template = { os_name = {"foo" = "host.vars.os$"} }

[2024-09-13 11:39:38 +0200] information/ConfigItem: Committing config item(s).
[2024-09-13 11:39:38 +0200] critical/config: Error: Operator + cannot be applied to values of type 'String' and 'Dictionary'
[2024-09-13 11:39:38 +0200] critical/config: 1 error
[2024-09-13 11:39:38 +0200] critical/cli: Config validation failed. Re-run with 'icinga2 daemon -C' after fixing the config.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my testing netsted dictionarys worked just fine when I remember correctly, but I'm not sure about arrays so I will test both cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is indeed supported, then you probably need to adjust validation errors, i.e. notice that in my example config snippet the opening $ is missing and when trying to produce an error message, you use the + operator to concatenate string with the nested dictionary ("Closing $ not found in macro format string '" + pair.second and pair.second is the nested dictionary in this case).

Copy link
Author

@SebastianOpeni SebastianOpeni Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My tests had the following results:

  • 1st level nested dictionaries are supported
    service_tags_template= { a = { b = "c" } } => tags.a.b = "c"
  • 2nd-level nested dictionaries are valid, but interpreted as (multi line) strings contained in the first nested dictionary.
    service_tags_template= { a = { b = { c = "d" } } } => tags.a.b = "{ c= "d" }"
  • arrays are also valid
    service_tags_template= { a = ["b", "c"] } => tags.a = ["b", "c"]

All of them are possible to contain macros therefore I would need a Macro Validator similar to MacroProcessor::ValidateCustomVars.

Would you prefer me:

  • rewriting a similar method in the elastic-search-writer
  • or creating a more general method MacroProcessor::ValidateMacroObject (or similar name) that gets called by my validator methods and also by MacroProcessor::ValidateCustomVars?

I would prefer the second option, but it would mean I change the MacroProcessor Class so I wanted to check back with you first.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather question the support for endlessly nested dicts in general before you do such a big change. As far as I'm concerned, I would just accept simple key => value pairs, but I don't know all the use cases you're going to need that for. So my question to you: is it worth making that lot of major code changes and probably investing even more time for testing just to support nested dicts/arrays?

I've looked at some other writers, and none of them support nested dictionaries up to unknown levels. So, if you absolutely need nested tags, couldn't you use such "tags.a.b.c.d" = "$foo$" as simple key-value pairs? This would really simplify the whole thing.

@@ -37,6 +40,7 @@ class ElasticsearchWriter final : public ObjectImpl<ElasticsearchWriter>
std::mutex m_DataBufferMutex;

void AddCheckResult(const Dictionary::Ptr& fields, const Checkable::Ptr& checkable, const CheckResult::Ptr& cr);
void AddTemplateTags(const Dictionary::Ptr& fields, const Host::Ptr& host, const Service::Ptr& service, const CheckResult::Ptr& cr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also merge host and service parameters by using Checkable::Ptr instead, just like the other methods in here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true and I also thought about doing so.
My reasoning was the following:
For the Resolver inside of the method I need to get the Host::Ptr and Service::Ptr from the Checkable::Ptr like it is done in other places.
But at all sources where AddTemplateTags will be called from this Host and Service retrieval has been done already just a couple of lines above.
So I would do the same "conversion" multiple times and therefore opted to call the Method with Host::Ptr and Service::Ptr directly.
If you would prefer the Checkable::Ptr way I can also implement it that way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you would prefer the Checkable::Ptr way I can also implement it that way.

The thing is, currently it looks like as the service parameter is always required and implies that it may never be a nullptr, thus I would either use Checkable::ptr instead and do the one-line casting again (my preferred variant) or make the service parameter optional.

ObjectLock olock(tags);
for (const Dictionary::Pair& pair : tags) {
if (!MacroProcessor::ValidateMacroString(pair.second))
BOOST_THROW_EXCEPTION(ValidationError(this, { "host_tags_template", pair.first }, "Closing $ not found in macro format string '" + pair.second));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing + "'." after pair.second (this applies to the service tags validation down below as well).

@@ -131,6 +132,36 @@ void ElasticsearchWriter::Pause()
ObjectImpl<ElasticsearchWriter>::Pause();
}

void ElasticsearchWriter::AddTemplateTags(const Dictionary::Ptr& fields, const Host::Ptr& host, const Service::Ptr& service, const CheckResult::Ptr& cr)
{
MacroProcessor::ResolverList resolvers;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can declare this above or below the ObjectLock olock ... within the if block instead.

@yhabteab yhabteab added this to the 2.15.0 milestone Sep 13, 2024
@yhabteab yhabteab added the enhancement New feature or request label Sep 13, 2024
@SebastianOpeni
Copy link
Author

Hi thanks for your review :)
I am currently working on your remarks but might have some questions beforehand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/elastic Events to Elasticsearch cla/signed enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support host and service templates to send variables to Elasticsearch
4 participants