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

Make StatsdClient more convenient to use #45

Closed
robinst opened this issue Jan 4, 2017 · 5 comments
Closed

Make StatsdClient more convenient to use #45

robinst opened this issue Jan 4, 2017 · 5 comments
Assignees
Milestone

Comments

@robinst
Copy link
Contributor

robinst commented Jan 4, 2017

I'm using this crate to add metrics to a small server application that uses the Iron framework.

For a request handler, I have a struct that implements Iron's Handler trait (note that it needs to be Send + Sync because it's used for handling requests in different threads).

In the handler struct, I keep things that are needed when handling the requests. One of these things is a slog Logger. The nice thing about it is that I can construct it when starting up the application and clone() it when I put it in the struct. And because it's Send + Sync, it works nicely.

For metrics, I started out with putting a StatsdClient<QueuingMetricSink> into the handler struct.
But then ideally, for testing, I'd just want to use a StatsdClient<NopMetricSink> instead.

So what I ended up with in the end is a struct like this, with some methods that delegate to the client:

#[derive(Clone)]
pub struct Metrics {
    client: Arc<MetricClient + Send + Sync>,
}

Using that, I can easily construct a client that uses NopMetricSink if I want to disable metrics.

So I'm wondering if it would be generally more useful if StatsdClient itself didn't come with generics but instead wrapped its sink in an Arc (see the implementation of Logger).

That would also make it nicer when code needs to pass a StatsdClient around as an argument/field (which happens in my code base and I'd expect in most real-world uses of this).

What do you think?

@56quarters
Copy link
Owner

Ha, funny you should mention this. I was just thinking about how to add some sort of MetricFormatter trait + impl to StatsdClient for #41 and it seemed a little ugly to have to start passing another generic param around.

Getting rid of the generic param and wrapping the sink in Arc (as well as making the client Clone) makes sense to me. Since this is a breaking change it would probably end up in 0.10.0 or later.

@56quarters
Copy link
Owner

The only problem I see with wrapping the sink in an Arc<MetricSink + Sync + Send> is that the AsyncMetricSink, which uses a thread pool, is not Sync. Since it uses a std::sync::mpsc::Sender instance, it relies on being .cloned() between threads.

So, AsyncMetricSink is not compatible with using an Arc<MetricSink + Sync + Send> in the client struct. But, I've been wanting to get rid of AsyncMetricSink anyway.

So my plan is to deprecate AsyncMetricSink (per #34) and release version 0.10.0. After that I'll remove it and make this change in version 0.11.0.

@56quarters 56quarters added this to the 0.11.0 milestone Jan 4, 2017
@robinst
Copy link
Contributor Author

robinst commented Jan 4, 2017

Yay, excellent!

@56quarters 56quarters self-assigned this Jan 10, 2017
56quarters added a commit that referenced this issue Jan 11, 2017
Remove the generic type `<T: MetricSink>` from the StatsdClient to make it more
ergonomic to use.

Prior to this, the easiest way to use the client was to put it behind a pointer
of some kind and reference it like `Box<MetricClient>` or
`Arc<MetricClient + Sync + Send>`. This is still possible but is now not required.
Users of the client may simply refer to it directly without needing to include
the concrete type of the `MetricSink`: `fn foo(some_param: StatsdClient) {}`

This commit also introduces some documentation for the `StatsdClient` that
describes the various ways this client can be shared between multiple threads.

Fixes #45
@56quarters
Copy link
Owner

Hey @robinst,

I submitted a PR to remove the generic param from the client (#52) if you like to check it out. The biggest change was adding some docs to the client on the ways that it could be shared between threads, based on the use cases you've described here. Let me know what you think. Thanks!

56quarters added a commit that referenced this issue Jan 11, 2017
Remove the generic type `<T: MetricSink>` from the StatsdClient to make it more
ergonomic to use.

Prior to this, the easiest way to use the client was to put it behind a pointer
of some kind and reference it like `Box<MetricClient>` or
`Arc<MetricClient + Sync + Send>`. This is still possible but is now not required.
Users of the client may simply refer to it directly without needing to include
the concrete type of the `MetricSink`: `fn foo(some_param: StatsdClient) {}`

This commit also introduces some documentation for the `StatsdClient` that
describes the various ways this client can be shared between multiple threads.

Fixes #45
@robinst
Copy link
Contributor Author

robinst commented Jan 11, 2017

Looks good! Just had a single comment. Like the docs as well, very nice.

56quarters added a commit that referenced this issue Jan 11, 2017
Remove the generic type `<T: MetricSink>` from the StatsdClient to make it more
ergonomic to use.

Prior to this, the easiest way to use the client was to put it behind a pointer
of some kind and reference it like `Box<MetricClient>` or
`Arc<MetricClient + Sync + Send>`. This is still possible but is now not required.
Users of the client may simply refer to it directly without needing to include
the concrete type of the `MetricSink`: `fn foo(some_param: StatsdClient) {}`

This commit also introduces some documentation for the `StatsdClient` that
describes the various ways this client can be shared between multiple threads.

Fixes #45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants