1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! Dispatch metrics to multiple sinks.

use core::*;

/// Two chains of different types can be combined in a tuple.
/// The chains will act as one, each receiving calls in the order the appear in the tuple.
/// For more than two types, make tuples of tuples, "Yo Dawg" style.
impl<M1, M2> From<(Chain<M1>, Chain<M2>)> for Chain<(M1, M2)>
where
    M1: 'static + Clone + Send + Sync,
    M2: 'static + Clone + Send + Sync,
{
    fn from(combo: (Chain<M1>, Chain<M2>)) -> Chain<(M1, M2)> {
        let combo0 = combo.0.clone();
        let combo1 = combo.1.clone();

        Chain::new(
            move |kind, name, rate| {
                (
                    combo.0.define_metric(kind, name, rate),
                    combo.1.define_metric(kind, &name, rate),
                )
            },
            move |buffered| {
                let scope0 = combo0.open_scope(buffered);
                let scope1 = combo1.open_scope(buffered);

                ControlScopeFn::new(move |cmd| match cmd {
                    ScopeCmd::Write(metric, value) => {
                        let metric: &(M1, M2) = metric;
                        scope0.write(&metric.0, value);
                        scope1.write(&metric.1, value);
                    }
                    ScopeCmd::Flush => {
                        scope0.flush();
                        scope1.flush();
                    }
                })
            },
        )
    }
}

/// Multiple chains of the same type can be combined in a slice.
/// The chains will act as one, each receiving calls in the order the appear in the slice.
impl<'a, M> From<&'a [Chain<M>]> for Chain<Vec<M>>
where
    M: 'static + Clone + Send + Sync,
{
    fn from(chains: &'a [Chain<M>]) -> Chain<Vec<M>> {
        let chains = chains.to_vec();
        let chains2 = chains.clone();

        Chain::new(
            move |kind, name, rate| {
                let mut metric = Vec::with_capacity(chains.len());
                for chain in &chains {
                    metric.push(chain.define_metric(kind, name, rate));
                }
                metric
            },
            move |buffered| {
                let mut scopes = Vec::with_capacity(chains2.len());
                for chain in &chains2 {
                    scopes.push(chain.open_scope(buffered));
                }

                ControlScopeFn::new(move |cmd| match cmd {
                    ScopeCmd::Write(metric, value) => {
                        let metric: &Vec<M> = metric;
                        for (i, scope) in scopes.iter().enumerate() {
                            scope.write(&metric[i], value)
                        }
                    },
                    ScopeCmd::Flush => for scope in &scopes {
                        scope.flush()
                    },
                })
            },
        )
    }
}