-
Notifications
You must be signed in to change notification settings - Fork 150
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
[IMPROVEMENT] Added exporter labels. #381
Conversation
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.
Overall, a good start! You covered a lot of the basic functionality and even added tests!!!
Part of the challenge for this (and Promgen overall) is how to make it easy, to modify a complicated configuration. There are lots of edge cases to consider. One that I quickly noticed, is that while you call out __param_
labels (good!) they're not actually taken into account when using the Exporter text button, which could be quite confusing when Promgen and Prometheus scrape things differently.
That combined with the other comment about displaying the custom labels (and not just using title=
attribute, I think we still need to think through the exact workflow a little more.
I think my next two days will be a little busy, but hopefully that gives you some good feedback. I'll try to circle back to this PR in a few days.
{{ labels_formset.management_form }} | ||
<div class="panel panel-default"> | ||
<div class="panel-heading" role="tab" id="labels-formset-panel-header"> | ||
<a role="button" data-toggle="collapse" href="#labels-formset-panel" aria-expanded="false" |
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.
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.
What adjustments you want to make?
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 main issue for me is the scrape exporter code. First of all there is a TODO in the code. Probably API /rest/project/<slug>/scrape
shoult know nothing about exporter register form fields and should receive a POST with body like {"host":"blackbox", "port":9115, "scheme": "https", "path": "/probe", "query": {"target": "prometheus.io"}}
. If so, then ExporterScrape
class could build the POST body from register exporter form then query API and return API response. Is that OK?
Maybe it is better to add a field is_parameter
to ExporterLabel
? In that case user is no need any more to use a prefix __param_
and all logic about prefix could be moved to prometheus render_config
function.
Also I have a question about API /rest/project/<slug>/scrape
. Why exporter's id is omitted? The url could be /rest/project/<slug>/exporter/<slug>/scrape
. In that case all url logic could be encapsulated in an Exporter
itself.
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 reason the scrape code is as is, is because you can use the test
button before it has been saved to the database, so we need to be able to POST the data to a test input when we don't already have an exporter_id.
@@ -10,7 +10,9 @@ | |||
<th colspan="4">Actions</th> | |||
</tr> | |||
{% for exporter in project.exporter_set.all %} | |||
<tr {% if not exporter.enabled %}class="promgen-disabled"{% endif %}> | |||
<tr {% if not exporter.enabled %}class="promgen-disabled"{% endif %} |
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.
Even though we use the title=
attribute in a few places to show extra information, I think in this case, additional labels are quite important, and we need to figure out how to make them always visible. Part of the challenge though is we do not currently have a lot of space there, so still thinking if we need to have a toggle collapse menu for it or not.
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.
Will button Labels
be OK? Button
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.
Button with dropdown table added.
promgen/tests/test_prometheus.py
Outdated
def setUp(self, mock_signal): | ||
user_id = 999 | ||
user = self.add_force_login(id=user_id, username='Tester') | ||
self.__create_services([ |
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.
Instead of having all this structure in code, we should really be using fixtures for the tests. (Older, existing tests should also be migrated to fixtures but that's something I should clean up)
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.
OK, I'll use fixtures.
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.
Done
New exporter scraping is fixed but scraping for existed exporters is still not working. We have to decide how to deal with it. I think we have two different types of scraping, one for existed exporters and another for new ones. Probably we have to scrape new exporters using my solution and create API especially for existed exporters. |
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.
Moving some of the data to fixtures helps clean up the tests a lot. This is great!
I don't think we want to depend on a is_parameter
though, since I think that will add a good deal of confusion.
I did a quick pass today, but I will likely have to wait until next week to do a more detailed pass. I have a few tasks that will likely take the rest of my attention this week. Thank you for your patience 🙇
promgen/forms.py
Outdated
widgets = { | ||
'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Name'}), | ||
'value': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Value'}), | ||
'is_parameter': forms.CheckboxInput() |
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.
I think we don't want to use a parameter here (and then later build a string). I think having this as a toggle, and then try to generate strings from this later is confusing. If a user inputs a label as foo
or __param_foo
or __invalid_foo
then that should be the exact name they see, and the exact name that is written into the Prometheus target.
We do however need to make sure we pass along the parameter when someone clicks the test version so we'll likely need to filter on that.
# psudo code
params = {}
for key in labels:
if key.startswith('__param'):
params[ key[:7] ] = labels[key]
I think this will cause the least amount of confusion in the long run.
promgen/forms.py
Outdated
continue | ||
if form.cleaned_data.get('is_parameter'): | ||
if name in parameters_names: | ||
e = ValidationError('Duplicated name', code='invalid') |
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.
I think I need to try to test this on my own, but something seems a bit off at first glance. I think all the checks for duplicated can probably just be left to the database and you shouldn't need custom logic in here.
promgen/models.py
Outdated
value = models.CharField( | ||
max_length=128, | ||
) | ||
is_parameter = models.BooleanField(default=False) |
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.
as mentioned above, I think having a toggle for this is going to be more confusing to the user, than doing a bit of filtering on key.startswith('__param')
promgen/prometheus.py
Outdated
@@ -132,12 +132,21 @@ def render_config(service=None, project=None): | |||
if exporter.path: | |||
labels["__metrics_path__"] = exporter.path | |||
|
|||
for label in exporter.exporterlabel_set.all(): | |||
if label.name not in labels: | |||
label_name = '__param_{}'.format(label.name) if label.is_parameter else label.name |
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.
As mentioned above, I think we don't want to use is_parameter
but filter on __param_
instead.
{{ labels_formset.management_form }} | ||
<div class="panel panel-default"> | ||
<div class="panel-heading" role="tab" id="labels-formset-panel-header"> | ||
<a role="button" data-toggle="collapse" href="#labels-formset-panel" aria-expanded="false" |
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 reason the scrape code is as is, is because you can use the test
button before it has been saved to the database, so we need to be able to POST the data to a test input when we don't already have an exporter_id.
promgen/tests/test_prometheus.py
Outdated
|
||
def test_create_config(self): | ||
config = prometheus.create_config() | ||
self.assertEqual(config, [ |
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.
Thanks!! Moving most of it to a filter really helps clean up the code. I think this config though can also be cleaned up a bit. You should be able to use our help function to put these test configurations as json as well
TEST_CONFIG = tests.Data('examples', 'test-targets.json').json()
or something similar
I have removed field |
Exporters scraping is working via new REST endpoint. The old endpoint is still exists and could be removed if new one is OK. |
I apologize for the long delay without comment. I have not forgotten this PR, I have just been preoccupied with other work tasks which have made it more difficult to prioritize this. Advanced users may have specific, legitimate use cases for this, there is also a large set of less advanced users who will not understand the implications and are very likely to make things more complicated by adding additional custom labels. I'm somewhat reluctant to merge as is, again not because the idea or code are bad, but because we need to be very careful that we can clearly communicate to the user when this feature should be used (since it likely should not be used in the most common cases). Unfortunately, this April may also be a little bit scattered in terms of ability so I can not currently commit to when I'll be able to think through all the implications of this change. 🙇 |
To resolve issues #346 and partially #180