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

Replace notify.Factory with a build function that accepts typed configuration #63

Merged
merged 17 commits into from
Mar 28, 2023

Conversation

yuri-tceretian
Copy link
Contributor

@yuri-tceretian yuri-tceretian commented Feb 14, 2023

Based on changes made in #61 and #62.
This PR introduces a factory function notify.BuildReceiverIntegrations that accepts parsed receiver configuration and creates Integrations.

Now, this looks pretty much closer to how upstream Alertmanager creates integrations.

Some notable changes:

  • All notifier constructors are replaced to accept only arguments they need instead of FactoryConfig.
  • FactoryConfig and the structs that it uses are deleted. Function GetDecryptedValueFn moved to notify package where it is used only once, which will make it simpler to delete in future.
  • Instead if NotificationSender there are two interfaces WebhookSender and EmailSender. In vanilla Alertmanager they are different for each notifier (actually, each notifier creates one by itself). Therefore, instead of accepting a single instance of senders BuildReceiverIntegrations now accepts factory functions, which can return an error. For example, lin in upstream Alertmanager https://github.com/prometheus/alertmanager/blob/41eb1213bb1c7ce0aa9e6464e297976d9c81cfe5/notify/webhook/webhook.go#L46

@yuri-tceretian yuri-tceretian self-assigned this Feb 14, 2023
@yuri-tceretian yuri-tceretian force-pushed the yuri-tceretian/typed-factory branch 4 times, most recently from 95dc30b to 4684ec2 Compare March 8, 2023 00:03
@yuri-tceretian yuri-tceretian marked this pull request as ready for review March 8, 2023 00:18
@yuri-tceretian yuri-tceretian force-pushed the yuri-tceretian/typed-factory branch from 4684ec2 to bc56f06 Compare March 8, 2023 00:31
@@ -1,6 +1,6 @@
package logging

type LoggerFactory func(ctx ...interface{}) Logger
type LoggerFactory func(loggerName string, ctx ...interface{}) Logger
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this makes it clear that first element is always logger name whereas the remaining go to context (that's how it is implemented in Grafana)

Copy link
Contributor

Choose a reason for hiding this comment

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

I like this change, but wouldn't it mean that we'll be using a different interface than the one defined in Grafana's infra package? In order to use the logger, we would have to add this string as the first item in the ctx slice.
I don't think it's a big deal, just want to make sure we're aware of this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Regularly, in the logging context is a slice of tuples. go-kit adds {Missing} if slice size is odd. However, In Grafana logger assumes that the first element is not a tuple's label but a logger name and automatically adds the logger label. However, this package can (and will) use a different logger implementation but usages of this interface still assume that the first element of the context is a logger. This change makes this interface more explicit.

I like this change, but wouldn't it mean that we'll be using a different interface than the one defined in Grafana's infra package?

There is no interface for New method in infra. What I do here is basically define it.

https://github.com/grafana/grafana/blob/862a6a2fa625100b690c5a48a9b12e7a7dd42041/pkg/infra/log/log.go#L231-L238

}
createIntegration(idx, cfg, func(logger logging.Logger) notificationChannel {
return f(logger, w)
})
Copy link
Contributor Author

Choose a reason for hiding this comment

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

these to anonymous methods help reduce duplicated code below.

// GetDecryptedValueFn is a function that returns the decrypted value of
// the given key. If the key is not present, then it returns the fallback value.
type GetDecryptedValueFn func(ctx context.Context, sjd map[string][]byte, key string, fallback string) string

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function is moved from the receivers package because it is not used there anymore.

@yuri-tceretian yuri-tceretian force-pushed the yuri-tceretian/typed-factory branch from c6f6f90 to dbee25f Compare March 15, 2023 19:14
Copy link
Contributor

@santihernandezc santihernandezc left a comment

Choose a reason for hiding this comment

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

I like the idea of passing explicit values to the factory function instead of a FactoryConfig struct.
I requested a few comments to be added, but apart from that I think it's good to go!

@@ -1,6 +1,6 @@
package logging

type LoggerFactory func(ctx ...interface{}) Logger
type LoggerFactory func(loggerName string, ctx ...interface{}) Logger
Copy link
Contributor

Choose a reason for hiding this comment

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

I like this change, but wouldn't it mean that we'll be using a different interface than the one defined in Grafana's infra package? In order to use the logger, we would have to add this string as the first item in the ctx slice.
I don't think it's a big deal, just want to make sure we're aware of this.

notify/factory.go Outdated Show resolved Hide resolved
notify/factory.go Outdated Show resolved Hide resolved
notify/factory.go Outdated Show resolved Hide resolved
notify/factory.go Outdated Show resolved Hide resolved
notify/factory.go Outdated Show resolved Hide resolved
Copy link
Collaborator

@gotjosh gotjosh left a comment

Choose a reason for hiding this comment

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

LGTM

Base: receivers.NewBase(meta),
tmpl: template,
log: logger,
ns: sender,
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: This is called sender but the variable is installed called ns - this comment applies to all the others that use the webhook sender.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will address it in a follow up PR as this rename will cause changes in other places.

receivers/slack/slack.go Outdated Show resolved Hide resolved
receivers/discord/discord.go Outdated Show resolved Hide resolved
settings: settings,
logger: fc.Logger,
}, nil
Base: receivers.NewBase(meta),
Copy link
Collaborator

Choose a reason for hiding this comment

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

we filed #70 due to some problems we saw while reviewing this.

notify/factory.go Outdated Show resolved Hide resolved
// It returns a slice of Integration objects, one for each notification channel, along with any errors that occurred.
func BuildReceiverIntegrations(
receiver GrafanaReceiverConfig,
tmpl *template.Template,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
tmpl *template.Template,
tmpl *alerting.Template,

you need the local types otherwise you'll import the alertmanage directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will address it in a follow-up PR as it touches many lines.

Comment on lines +41 to +42
newWebhookSender func(n receivers.Metadata) (receivers.WebhookSender, error),
newEmailSender func(n receivers.Metadata) (receivers.EmailSender, error),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think these functions should use primitives, such as:

func(ctx context.Context, client *http.Client, url string, body io.Reader) (*http.Response, error)

Instead of whatever interface was defined by Grafana with the WebhookSender and the EmailSender.

notify/factory.go Outdated Show resolved Hide resolved
notify/factory.go Outdated Show resolved Hide resolved
notify/factory.go Outdated Show resolved Hide resolved
Copy link
Contributor

@santihernandezc santihernandezc left a comment

Choose a reason for hiding this comment

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

All of my previous comments have been addressed 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants