Browse Source

Add support of EventDomainFronting event

tags/v2.0.0-rc1
9seconds 5 years ago
parent
commit
bef14bd009

+ 7
- 5
events/event_stream.go View File

60
 	return rv
60
 	return rv
61
 }
61
 }
62
 
62
 
63
-func eventStreamProcessor(ctx context.Context, eventChan <-chan mtglib.Event, observer Observer) {
63
+func eventStreamProcessor(ctx context.Context, eventChan <-chan mtglib.Event, observer Observer) { // nolint: cyclop
64
 	defer observer.Shutdown()
64
 	defer observer.Shutdown()
65
 
65
 
66
 	for {
66
 	for {
69
 			return
69
 			return
70
 		case evt := <-eventChan:
70
 		case evt := <-eventChan:
71
 			switch typedEvt := evt.(type) {
71
 			switch typedEvt := evt.(type) {
72
-			case mtglib.EventStart:
73
-				observer.EventStart(typedEvt)
74
-			case mtglib.EventConnectedToDC:
75
-				observer.EventConnectedToDC(typedEvt)
76
 			case mtglib.EventTraffic:
72
 			case mtglib.EventTraffic:
77
 				observer.EventTraffic(typedEvt)
73
 				observer.EventTraffic(typedEvt)
74
+			case mtglib.EventStart:
75
+				observer.EventStart(typedEvt)
78
 			case mtglib.EventFinish:
76
 			case mtglib.EventFinish:
79
 				observer.EventFinish(typedEvt)
77
 				observer.EventFinish(typedEvt)
78
+			case mtglib.EventConnectedToDC:
79
+				observer.EventConnectedToDC(typedEvt)
80
+			case mtglib.EventDomainFronting:
81
+				observer.EventDomainFronting(typedEvt)
80
 			case mtglib.EventIPBlocklisted:
82
 			case mtglib.EventIPBlocklisted:
81
 				observer.EventIPBlocklisted(typedEvt)
83
 				observer.EventIPBlocklisted(typedEvt)
82
 			case mtglib.EventConcurrencyLimited:
84
 			case mtglib.EventConcurrencyLimited:

+ 23
- 0
events/event_stream_test.go View File

90
 	time.Sleep(100 * time.Millisecond)
90
 	time.Sleep(100 * time.Millisecond)
91
 }
91
 }
92
 
92
 
93
+func (suite *EventStreamTestSuite) TestEventDomainFronting() {
94
+	evt := mtglib.EventDomainFronting{
95
+		CreatedAt: time.Now(),
96
+		ConnID:    "connID",
97
+	}
98
+
99
+	for _, v := range []*ObserverMock{suite.observerMock1, suite.observerMock2} {
100
+		v.
101
+			On("EventDomainFronting", mock.Anything).
102
+			Once().
103
+			Run(func(args mock.Arguments) {
104
+				caught := args.Get(0).(mtglib.EventDomainFronting)
105
+
106
+				suite.Equal(evt.CreatedAt, caught.CreatedAt)
107
+				suite.Equal(evt.ConnID, caught.ConnID)
108
+				suite.Equal(evt.StreamID(), caught.StreamID())
109
+			})
110
+	}
111
+
112
+	suite.stream.Send(suite.ctx, evt)
113
+	time.Sleep(100 * time.Millisecond)
114
+}
115
+
93
 func (suite *EventStreamTestSuite) TestEventTraffic() {
116
 func (suite *EventStreamTestSuite) TestEventTraffic() {
94
 	evt := mtglib.EventTraffic{
117
 	evt := mtglib.EventTraffic{
95
 		CreatedAt: time.Now(),
118
 		CreatedAt: time.Now(),

+ 1
- 0
events/init.go View File

6
 	EventStart(mtglib.EventStart)
6
 	EventStart(mtglib.EventStart)
7
 	EventFinish(mtglib.EventFinish)
7
 	EventFinish(mtglib.EventFinish)
8
 	EventConnectedToDC(mtglib.EventConnectedToDC)
8
 	EventConnectedToDC(mtglib.EventConnectedToDC)
9
+	EventDomainFronting(mtglib.EventDomainFronting)
9
 	EventTraffic(mtglib.EventTraffic)
10
 	EventTraffic(mtglib.EventTraffic)
10
 	EventConcurrencyLimited(mtglib.EventConcurrencyLimited)
11
 	EventConcurrencyLimited(mtglib.EventConcurrencyLimited)
11
 	EventIPBlocklisted(mtglib.EventIPBlocklisted)
12
 	EventIPBlocklisted(mtglib.EventIPBlocklisted)

+ 4
- 0
events/init_test.go View File

17
 	o.Called(evt)
17
 	o.Called(evt)
18
 }
18
 }
19
 
19
 
20
+func (o *ObserverMock) EventDomainFronting(evt mtglib.EventDomainFronting) {
21
+	o.Called(evt)
22
+}
23
+
20
 func (o *ObserverMock) EventTraffic(evt mtglib.EventTraffic) {
24
 func (o *ObserverMock) EventTraffic(evt mtglib.EventTraffic) {
21
 	o.Called(evt)
25
 	o.Called(evt)
22
 }
26
 }

+ 15
- 0
events/multi_observer.go View File

40
 	wg.Wait()
40
 	wg.Wait()
41
 }
41
 }
42
 
42
 
43
+func (m multiObserver) EventDomainFronting(evt mtglib.EventDomainFronting) {
44
+	wg := &sync.WaitGroup{}
45
+	wg.Add(len(m.observers))
46
+
47
+	for _, v := range m.observers {
48
+		go func(obs Observer) {
49
+			defer wg.Done()
50
+
51
+			obs.EventDomainFronting(evt)
52
+		}(v)
53
+	}
54
+
55
+	wg.Wait()
56
+}
57
+
43
 func (m multiObserver) EventTraffic(evt mtglib.EventTraffic) {
58
 func (m multiObserver) EventTraffic(evt mtglib.EventTraffic) {
44
 	wg := &sync.WaitGroup{}
59
 	wg := &sync.WaitGroup{}
45
 	wg.Add(len(m.observers))
60
 	wg.Add(len(m.observers))

+ 1
- 0
events/noop.go View File

19
 
19
 
20
 func (n noopObserver) EventStart(_ mtglib.EventStart)                           {}
20
 func (n noopObserver) EventStart(_ mtglib.EventStart)                           {}
21
 func (n noopObserver) EventConnectedToDC(_ mtglib.EventConnectedToDC)           {}
21
 func (n noopObserver) EventConnectedToDC(_ mtglib.EventConnectedToDC)           {}
22
+func (n noopObserver) EventDomainFronting(_ mtglib.EventDomainFronting)         {}
22
 func (n noopObserver) EventTraffic(_ mtglib.EventTraffic)                       {}
23
 func (n noopObserver) EventTraffic(_ mtglib.EventTraffic)                       {}
23
 func (n noopObserver) EventFinish(_ mtglib.EventFinish)                         {}
24
 func (n noopObserver) EventFinish(_ mtglib.EventFinish)                         {}
24
 func (n noopObserver) EventConcurrencyLimited(_ mtglib.EventConcurrencyLimited) {}
25
 func (n noopObserver) EventConcurrencyLimited(_ mtglib.EventConcurrencyLimited) {}

+ 6
- 0
events/noop_test.go View File

31
 			RemoteIP:  net.ParseIP("127.1.0.1"),
31
 			RemoteIP:  net.ParseIP("127.1.0.1"),
32
 			DC:        2,
32
 			DC:        2,
33
 		},
33
 		},
34
+		"domain-fronting": mtglib.EventDomainFronting{
35
+			CreatedAt: time.Now(),
36
+			ConnID:    "connID",
37
+		},
34
 		"traffic": mtglib.EventTraffic{
38
 		"traffic": mtglib.EventTraffic{
35
 			CreatedAt: time.Now(),
39
 			CreatedAt: time.Now(),
36
 			ConnID:    "connID",
40
 			ConnID:    "connID",
76
 				observer.EventStart(typedEvt)
80
 				observer.EventStart(typedEvt)
77
 			case mtglib.EventConnectedToDC:
81
 			case mtglib.EventConnectedToDC:
78
 				observer.EventConnectedToDC(typedEvt)
82
 				observer.EventConnectedToDC(typedEvt)
83
+			case mtglib.EventDomainFronting:
84
+				observer.EventDomainFronting(typedEvt)
79
 			case mtglib.EventFinish:
85
 			case mtglib.EventFinish:
80
 				observer.EventFinish(typedEvt)
86
 				observer.EventFinish(typedEvt)
81
 			case mtglib.EventConcurrencyLimited:
87
 			case mtglib.EventConcurrencyLimited:

+ 3
- 3
mtglib/conns.go View File

9
 	"time"
9
 	"time"
10
 )
10
 )
11
 
11
 
12
-type connTelegramTraffic struct {
12
+type connTraffic struct {
13
 	net.Conn
13
 	net.Conn
14
 
14
 
15
 	connID string
15
 	connID string
17
 	ctx    context.Context
17
 	ctx    context.Context
18
 }
18
 }
19
 
19
 
20
-func (c connTelegramTraffic) Read(b []byte) (int, error) {
20
+func (c connTraffic) Read(b []byte) (int, error) {
21
 	n, err := c.Conn.Read(b)
21
 	n, err := c.Conn.Read(b)
22
 
22
 
23
 	if n > 0 {
23
 	if n > 0 {
32
 	return n, err // nolint: wrapcheck
32
 	return n, err // nolint: wrapcheck
33
 }
33
 }
34
 
34
 
35
-func (c connTelegramTraffic) Write(b []byte) (int, error) {
35
+func (c connTraffic) Write(b []byte) (int, error) {
36
 	n, err := c.Conn.Write(b)
36
 	n, err := c.Conn.Write(b)
37
 
37
 
38
 	if n > 0 {
38
 	if n > 0 {

+ 13
- 0
mtglib/events.go View File

62
 	return e.CreatedAt
62
 	return e.CreatedAt
63
 }
63
 }
64
 
64
 
65
+type EventDomainFronting struct {
66
+	CreatedAt time.Time
67
+	ConnID    string
68
+}
69
+
70
+func (e EventDomainFronting) StreamID() string {
71
+	return e.ConnID
72
+}
73
+
74
+func (e EventDomainFronting) Timestamp() time.Time {
75
+	return e.CreatedAt
76
+}
77
+
65
 type EventConcurrencyLimited struct {
78
 type EventConcurrencyLimited struct {
66
 	CreatedAt time.Time
79
 	CreatedAt time.Time
67
 }
80
 }

+ 10
- 0
mtglib/events_test.go View File

58
 	suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
58
 	suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
59
 }
59
 }
60
 
60
 
61
+func (suite *EventsTestSuite) TestEventDomainFronting() {
62
+	evt := mtglib.EventDomainFronting{
63
+		CreatedAt: time.Now(),
64
+		ConnID:    "CONNID",
65
+	}
66
+
67
+	suite.Equal("CONNID", evt.StreamID())
68
+	suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
69
+}
70
+
61
 func (suite *EventsTestSuite) TestEventConcurrencyLimited() {
71
 func (suite *EventsTestSuite) TestEventConcurrencyLimited() {
62
 	evt := mtglib.EventConcurrencyLimited{
72
 	evt := mtglib.EventConcurrencyLimited{
63
 		CreatedAt: time.Now(),
73
 		CreatedAt: time.Now(),

+ 14
- 2
mtglib/proxy.go View File

215
 	}
215
 	}
216
 
216
 
217
 	ctx.telegramConn = obfuscated2.Conn{
217
 	ctx.telegramConn = obfuscated2.Conn{
218
-		Conn: connTelegramTraffic{
218
+		Conn: connTraffic{
219
 			Conn:   conn,
219
 			Conn:   conn,
220
 			connID: ctx.connID,
220
 			connID: ctx.connID,
221
 			stream: p.eventStream,
221
 			stream: p.eventStream,
235
 	return nil
235
 	return nil
236
 }
236
 }
237
 
237
 
238
-func (p *Proxy) doDomainFronting(ctx context.Context, conn *connRewind) {
238
+func (p *Proxy) doDomainFronting(ctx *streamContext, conn *connRewind) {
239
+	p.eventStream.Send(p.ctx, EventDomainFronting{
240
+		CreatedAt: time.Now(),
241
+		ConnID:    ctx.connID,
242
+	})
243
+
239
 	conn.Rewind()
244
 	conn.Rewind()
240
 
245
 
241
 	frontConn, err := p.network.DialContext(ctx, "tcp", p.domainFrontAddress)
246
 	frontConn, err := p.network.DialContext(ctx, "tcp", p.domainFrontAddress)
245
 		return
250
 		return
246
 	}
251
 	}
247
 
252
 
253
+	frontConn = connTraffic{
254
+		Conn:   frontConn,
255
+		ctx:    ctx,
256
+		connID: ctx.connID,
257
+		stream: p.eventStream,
258
+	}
259
+
248
 	rel := relay.AcquireRelay(ctx,
260
 	rel := relay.AcquireRelay(ctx,
249
 		p.logger.Named("domain-fronting"), p.bufferSize, p.idleTimeout)
261
 		p.logger.Named("domain-fronting"), p.bufferSize, p.idleTimeout)
250
 	defer relay.ReleaseRelay(rel)
262
 	defer relay.ReleaseRelay(rel)

+ 6
- 4
stats/pools.go View File

4
 
4
 
5
 var streamInfoPool = sync.Pool{
5
 var streamInfoPool = sync.Pool{
6
 	New: func() interface{} {
6
 	New: func() interface{} {
7
-		return streamInfo{}
7
+		return &streamInfo{
8
+			tags: make(map[string]string),
9
+		}
8
 	},
10
 	},
9
 }
11
 }
10
 
12
 
11
-func acquireStreamInfo() streamInfo {
12
-	return streamInfoPool.Get().(streamInfo)
13
+func acquireStreamInfo() *streamInfo {
14
+	return streamInfoPool.Get().(*streamInfo)
13
 }
15
 }
14
 
16
 
15
-func releaseStreamInfo(info streamInfo) {
17
+func releaseStreamInfo(info *streamInfo) {
16
 	info.Reset()
18
 	info.Reset()
17
 	streamInfoPool.Put(info)
19
 	streamInfoPool.Put(info)
18
 }
20
 }

+ 47
- 17
stats/prometheus.go View File

13
 )
13
 )
14
 
14
 
15
 type prometheusProcessor struct {
15
 type prometheusProcessor struct {
16
-	streams map[string]streamInfo
16
+	streams map[string]*streamInfo
17
 	factory *PrometheusFactory
17
 	factory *PrometheusFactory
18
 }
18
 }
19
 
19
 
21
 	info := acquireStreamInfo()
21
 	info := acquireStreamInfo()
22
 
22
 
23
 	if evt.RemoteIP.To4() != nil {
23
 	if evt.RemoteIP.To4() != nil {
24
-		info[TagIPFamily] = TagIPFamilyIPv4
24
+		info.tags[TagIPFamily] = TagIPFamilyIPv4
25
 	} else {
25
 	} else {
26
-		info[TagIPFamily] = TagIPFamilyIPv6
26
+		info.tags[TagIPFamily] = TagIPFamilyIPv6
27
 	}
27
 	}
28
 
28
 
29
 	p.streams[evt.StreamID()] = info
29
 	p.streams[evt.StreamID()] = info
30
 
30
 
31
 	p.factory.metricClientConnections.
31
 	p.factory.metricClientConnections.
32
-		WithLabelValues(info[TagIPFamily]).
32
+		WithLabelValues(info.tags[TagIPFamily]).
33
 		Inc()
33
 		Inc()
34
 }
34
 }
35
 
35
 
39
 		return
39
 		return
40
 	}
40
 	}
41
 
41
 
42
-	info[TagTelegramIP] = evt.RemoteIP.String()
43
-	info[TagDC] = strconv.Itoa(evt.DC)
42
+	info.tags[TagTelegramIP] = evt.RemoteIP.String()
43
+	info.tags[TagDC] = strconv.Itoa(evt.DC)
44
 
44
 
45
 	p.factory.metricTelegramConnections.
45
 	p.factory.metricTelegramConnections.
46
-		WithLabelValues(info[TagTelegramIP], info[TagDC]).
46
+		WithLabelValues(info.tags[TagTelegramIP], info.tags[TagDC]).
47
+		Inc()
48
+}
49
+
50
+func (p prometheusProcessor) EventDomainFronting(evt mtglib.EventDomainFronting) {
51
+	info, ok := p.streams[evt.StreamID()]
52
+	if !ok {
53
+		return
54
+	}
55
+
56
+	info.isDomainFronted = true
57
+
58
+	p.factory.metricDomainFronting.Inc()
59
+	p.factory.metricDomainFrontingConnections.
60
+		WithLabelValues(info.tags[TagIPFamily]).
47
 		Inc()
61
 		Inc()
48
 }
62
 }
49
 
63
 
53
 		return
67
 		return
54
 	}
68
 	}
55
 
69
 
56
-	p.factory.metricTelegramTraffic.
57
-		WithLabelValues(info[TagTelegramIP], info[TagDC], getDirection(evt.IsRead)).
58
-		Add(float64(evt.Traffic))
70
+	direction := getDirection(evt.IsRead)
71
+
72
+	if info.isDomainFronted {
73
+		p.factory.metricDomainFrontingTraffic.
74
+			WithLabelValues(direction).
75
+			Add(float64(evt.Traffic))
76
+	} else {
77
+		p.factory.metricTelegramTraffic.
78
+			WithLabelValues(info.tags[TagTelegramIP], info.tags[TagDC], direction).
79
+			Add(float64(evt.Traffic))
80
+	}
59
 }
81
 }
60
 
82
 
61
 func (p prometheusProcessor) EventFinish(evt mtglib.EventFinish) {
83
 func (p prometheusProcessor) EventFinish(evt mtglib.EventFinish) {
70
 	}()
92
 	}()
71
 
93
 
72
 	p.factory.metricClientConnections.
94
 	p.factory.metricClientConnections.
73
-		WithLabelValues(info[TagIPFamily]).
95
+		WithLabelValues(info.tags[TagIPFamily]).
74
 		Dec()
96
 		Dec()
75
 
97
 
76
-	if telegramIP, ok := info[TagTelegramIP]; ok {
98
+	if info.isDomainFronted {
99
+		p.factory.metricDomainFrontingConnections.
100
+			WithLabelValues(info.tags[TagIPFamily]).
101
+			Dec()
102
+	} else if telegramIP, ok := info.tags[TagTelegramIP]; ok {
77
 		p.factory.metricTelegramConnections.
103
 		p.factory.metricTelegramConnections.
78
-			WithLabelValues(telegramIP, info[TagDC]).
104
+			WithLabelValues(telegramIP, info.tags[TagDC]).
79
 			Dec()
105
 			Dec()
80
 	}
106
 	}
81
 }
107
 }
89
 }
115
 }
90
 
116
 
91
 func (p prometheusProcessor) Shutdown() {
117
 func (p prometheusProcessor) Shutdown() {
92
-	p.streams = make(map[string]streamInfo)
118
+	for _, v := range p.streams {
119
+		releaseStreamInfo(v)
120
+	}
121
+
122
+	p.streams = make(map[string]*streamInfo)
93
 }
123
 }
94
 
124
 
95
 type PrometheusFactory struct {
125
 type PrometheusFactory struct {
110
 
140
 
111
 func (p *PrometheusFactory) Make() events.Observer {
141
 func (p *PrometheusFactory) Make() events.Observer {
112
 	return prometheusProcessor{
142
 	return prometheusProcessor{
113
-		streams: make(map[string]streamInfo),
143
+		streams: make(map[string]*streamInfo),
114
 		factory: p,
144
 		factory: p,
115
 	}
145
 	}
116
 }
146
 }
149
 		}, []string{TagTelegramIP, TagDC}),
179
 		}, []string{TagTelegramIP, TagDC}),
150
 		metricDomainFrontingConnections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
180
 		metricDomainFrontingConnections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
151
 			Namespace: metricPrefix,
181
 			Namespace: metricPrefix,
152
-			Name:      MetricDomainFronting,
153
-			Help:      "A number of connections which talk with front domain.",
182
+			Name:      MetricDomainFrontingConnections,
183
+			Help:      "A number of connections which talk to front domain.",
154
 		}, []string{TagIPFamily}),
184
 		}, []string{TagIPFamily}),
155
 
185
 
156
 		metricTelegramTraffic: prometheus.NewCounterVec(prometheus.CounterOpts{
186
 		metricTelegramTraffic: prometheus.NewCounterVec(prometheus.CounterOpts{

+ 60
- 1
stats/prometheus_test.go View File

54
 	suite.httpListener.Close()
54
 	suite.httpListener.Close()
55
 }
55
 }
56
 
56
 
57
-func (suite *PrometheusTestSuite) TestEventStartFinish() {
57
+func (suite *PrometheusTestSuite) TestTelegramPath() {
58
 	suite.prometheus.EventStart(mtglib.EventStart{
58
 	suite.prometheus.EventStart(mtglib.EventStart{
59
 		CreatedAt: time.Now(),
59
 		CreatedAt: time.Now(),
60
 		ConnID:    "connID",
60
 		ConnID:    "connID",
114
 	suite.Contains(data, `mtg_telegram_connections{dc="4",telegram_ip="10.0.0.1"} 0`)
114
 	suite.Contains(data, `mtg_telegram_connections{dc="4",telegram_ip="10.0.0.1"} 0`)
115
 }
115
 }
116
 
116
 
117
+func (suite *PrometheusTestSuite) TestDomainFrontingPath() {
118
+	suite.prometheus.EventStart(mtglib.EventStart{
119
+		CreatedAt: time.Now(),
120
+		ConnID:    "connID",
121
+		RemoteIP:  net.ParseIP("10.0.0.10"),
122
+	})
123
+	time.Sleep(100 * time.Millisecond)
124
+
125
+	data, err := suite.Get()
126
+	suite.NoError(err)
127
+	suite.Contains(data, `mtg_client_connections{ip_family="ipv4"} 1`)
128
+
129
+	suite.prometheus.EventDomainFronting(mtglib.EventDomainFronting{
130
+		CreatedAt: time.Now(),
131
+		ConnID:    "connID",
132
+	})
133
+	time.Sleep(100 * time.Millisecond)
134
+
135
+	data, err = suite.Get()
136
+	suite.NoError(err)
137
+	suite.Contains(data, `mtg_domain_fronting 1`)
138
+	suite.Contains(data, `mtg_domain_fronting_connections{ip_family="ipv4"} 1`)
139
+
140
+	suite.prometheus.EventTraffic(mtglib.EventTraffic{
141
+		CreatedAt: time.Now(),
142
+		ConnID:    "connID",
143
+		Traffic:   200,
144
+		IsRead:    true,
145
+	})
146
+	time.Sleep(100 * time.Millisecond)
147
+
148
+	data, err = suite.Get()
149
+	suite.NoError(err)
150
+	suite.Contains(data, `mtg_domain_fronting_traffic{direction="to_client"} 200`)
151
+
152
+	suite.prometheus.EventTraffic(mtglib.EventTraffic{
153
+		CreatedAt: time.Now(),
154
+		ConnID:    "connID",
155
+		Traffic:   100,
156
+		IsRead:    false,
157
+	})
158
+	time.Sleep(100 * time.Millisecond)
159
+
160
+	data, err = suite.Get()
161
+	suite.NoError(err)
162
+	suite.Contains(data, `mtg_domain_fronting_traffic{direction="from_client"} 100`)
163
+
164
+	suite.prometheus.EventFinish(mtglib.EventFinish{
165
+		CreatedAt: time.Now(),
166
+		ConnID:    "connID",
167
+	})
168
+	time.Sleep(100 * time.Millisecond)
169
+
170
+	data, err = suite.Get()
171
+	suite.NoError(err)
172
+	suite.Contains(data, `mtg_client_connections{ip_family="ipv4"} 0`)
173
+	suite.Contains(data, `mtg_domain_fronting_connections{ip_family="ipv4"} 0`)
174
+}
175
+
117
 func (suite *PrometheusTestSuite) TestEventConcurrencyLimited() {
176
 func (suite *PrometheusTestSuite) TestEventConcurrencyLimited() {
118
 	suite.prometheus.EventConcurrencyLimited(mtglib.EventConcurrencyLimited{
177
 	suite.prometheus.EventConcurrencyLimited(mtglib.EventConcurrencyLimited{
119
 		CreatedAt: time.Now(),
178
 		CreatedAt: time.Now(),

+ 38
- 12
stats/statsd.go View File

13
 )
13
 )
14
 
14
 
15
 type statsdProcessor struct {
15
 type statsdProcessor struct {
16
-	streams map[string]streamInfo
16
+	streams map[string]*streamInfo
17
 	client  *statsd.Client
17
 	client  *statsd.Client
18
 }
18
 }
19
 
19
 
21
 	info := acquireStreamInfo()
21
 	info := acquireStreamInfo()
22
 
22
 
23
 	if evt.RemoteIP.To4() != nil {
23
 	if evt.RemoteIP.To4() != nil {
24
-		info[TagIPFamily] = TagIPFamilyIPv4
24
+		info.tags[TagIPFamily] = TagIPFamilyIPv4
25
 	} else {
25
 	} else {
26
-		info[TagIPFamily] = TagIPFamilyIPv6
26
+		info.tags[TagIPFamily] = TagIPFamilyIPv6
27
 	}
27
 	}
28
 
28
 
29
 	s.streams[evt.StreamID()] = info
29
 	s.streams[evt.StreamID()] = info
39
 		return
39
 		return
40
 	}
40
 	}
41
 
41
 
42
-	info[TagTelegramIP] = evt.RemoteIP.String()
43
-	info[TagDC] = strconv.Itoa(evt.DC)
42
+	info.tags[TagTelegramIP] = evt.RemoteIP.String()
43
+	info.tags[TagDC] = strconv.Itoa(evt.DC)
44
 
44
 
45
 	s.client.GaugeDelta(MetricTelegramConnections,
45
 	s.client.GaugeDelta(MetricTelegramConnections,
46
 		1,
46
 		1,
48
 		info.T(TagDC))
48
 		info.T(TagDC))
49
 }
49
 }
50
 
50
 
51
+func (s statsdProcessor) EventDomainFronting(evt mtglib.EventDomainFronting) {
52
+	info, ok := s.streams[evt.StreamID()]
53
+	if !ok {
54
+		return
55
+	}
56
+
57
+	info.isDomainFronted = true
58
+
59
+	s.client.Incr(MetricDomainFronting, 1)
60
+	s.client.GaugeDelta(MetricDomainFrontingConnections,
61
+		1,
62
+		info.T(TagIPFamily))
63
+}
64
+
51
 func (s statsdProcessor) EventTraffic(evt mtglib.EventTraffic) {
65
 func (s statsdProcessor) EventTraffic(evt mtglib.EventTraffic) {
52
 	info, ok := s.streams[evt.StreamID()]
66
 	info, ok := s.streams[evt.StreamID()]
53
 	if !ok {
67
 	if !ok {
54
 		return
68
 		return
55
 	}
69
 	}
56
 
70
 
57
-	s.client.Incr(MetricTelegramTraffic,
58
-		int64(evt.Traffic),
59
-		info.T(TagTelegramIP),
60
-		info.T(TagDC),
61
-		statsd.StringTag(TagDirection, getDirection(evt.IsRead)))
71
+	directionTag := statsd.StringTag(TagDirection, getDirection(evt.IsRead))
72
+
73
+	if info.isDomainFronted {
74
+		s.client.Incr(MetricDomainFrontingTraffic,
75
+			int64(evt.Traffic),
76
+			directionTag)
77
+	} else {
78
+		s.client.Incr(MetricTelegramTraffic,
79
+			int64(evt.Traffic),
80
+			info.T(TagTelegramIP),
81
+			info.T(TagDC),
82
+			directionTag)
83
+	}
62
 }
84
 }
63
 
85
 
64
 func (s statsdProcessor) EventFinish(evt mtglib.EventFinish) {
86
 func (s statsdProcessor) EventFinish(evt mtglib.EventFinish) {
76
 		-1,
98
 		-1,
77
 		info.T(TagIPFamily))
99
 		info.T(TagIPFamily))
78
 
100
 
79
-	if _, ok := info[TagTelegramIP]; ok {
101
+	if info.isDomainFronted {
102
+		s.client.GaugeDelta(MetricDomainFrontingConnections,
103
+			-1,
104
+			info.T(TagIPFamily))
105
+	} else if _, ok := info.tags[TagTelegramIP]; ok {
80
 		s.client.GaugeDelta(MetricTelegramConnections,
106
 		s.client.GaugeDelta(MetricTelegramConnections,
81
 			-1,
107
 			-1,
82
 			info.T(TagTelegramIP),
108
 			info.T(TagTelegramIP),
119
 func (s StatsdFactory) Make() events.Observer {
145
 func (s StatsdFactory) Make() events.Observer {
120
 	return statsdProcessor{
146
 	return statsdProcessor{
121
 		client:  s.client,
147
 		client:  s.client,
122
-		streams: make(map[string]streamInfo),
148
+		streams: make(map[string]*streamInfo),
123
 	}
149
 	}
124
 }
150
 }
125
 
151
 

+ 57
- 2
stats/statsd_test.go View File

16
 	"github.com/stretchr/testify/suite"
16
 	"github.com/stretchr/testify/suite"
17
 )
17
 )
18
 
18
 
19
-const statsdSleepTime = 3 * statsd.DefaultFlushInterval
19
+const statsdSleepTime = 4 * statsd.DefaultFlushInterval
20
 
20
 
21
 type statsdFakeServer struct {
21
 type statsdFakeServer struct {
22
 	conn  *net.UDPConn
22
 	conn  *net.UDPConn
104
 	suite.statsdServer.Close()
104
 	suite.statsdServer.Close()
105
 }
105
 }
106
 
106
 
107
-func (suite *StatsdTestSuite) TestEventStartFinish() {
107
+func (suite *StatsdTestSuite) TestTelegramPath() {
108
 	suite.statsd.EventStart(mtglib.EventStart{
108
 	suite.statsd.EventStart(mtglib.EventStart{
109
 		CreatedAt: time.Now(),
109
 		CreatedAt: time.Now(),
110
 		ConnID:    "connID",
110
 		ConnID:    "connID",
152
 		"mtg.telegram_connections:-1|g|#telegram_ip:10.1.0.10,dc:2")
152
 		"mtg.telegram_connections:-1|g|#telegram_ip:10.1.0.10,dc:2")
153
 	suite.Contains(suite.statsdServer.String(),
153
 	suite.Contains(suite.statsdServer.String(),
154
 		"mtg.client_connections:-1|g|#ip_family:ipv4")
154
 		"mtg.client_connections:-1|g|#ip_family:ipv4")
155
+
156
+	suite.NotContains(suite.statsdServer.String(), "domain_fronting_traffic")
157
+	suite.NotContains(suite.statsdServer.String(), "domain_fronting_connections")
158
+}
159
+
160
+func (suite *StatsdTestSuite) TestDomainFrontingPath() {
161
+	suite.statsd.EventStart(mtglib.EventStart{
162
+		CreatedAt: time.Now(),
163
+		ConnID:    "connID",
164
+		RemoteIP:  net.ParseIP("10.0.0.10"),
165
+	})
166
+	time.Sleep(statsdSleepTime)
167
+	suite.Equal("mtg.client_connections:+1|g|#ip_family:ipv4", suite.statsdServer.String())
168
+
169
+	suite.statsd.EventDomainFronting(mtglib.EventDomainFronting{
170
+		CreatedAt: time.Now(),
171
+		ConnID:    "connID",
172
+	})
173
+	time.Sleep(statsdSleepTime)
174
+	suite.Contains(suite.statsdServer.String(), "mtg.domain_fronting:1|c")
175
+	suite.Contains(suite.statsdServer.String(),
176
+		`mtg.domain_fronting_connections:+1|g|#ip_family:ipv4`)
177
+
178
+	suite.statsd.EventTraffic(mtglib.EventTraffic{
179
+		CreatedAt: time.Now(),
180
+		ConnID:    "connID",
181
+		Traffic:   30,
182
+		IsRead:    true,
183
+	})
184
+	time.Sleep(statsdSleepTime)
185
+	suite.Contains(suite.statsdServer.String(),
186
+		`mtg.domain_fronting_traffic:30|c|#direction:to_client`)
187
+
188
+	suite.statsd.EventTraffic(mtglib.EventTraffic{
189
+		CreatedAt: time.Now(),
190
+		ConnID:    "connID",
191
+		Traffic:   90,
192
+		IsRead:    false,
193
+	})
194
+	time.Sleep(statsdSleepTime)
195
+	suite.Contains(suite.statsdServer.String(),
196
+		`mtg.domain_fronting_traffic:90|c|#direction:from_client`)
197
+
198
+	suite.statsd.EventFinish(mtglib.EventFinish{
199
+		CreatedAt: time.Now(),
200
+		ConnID:    "connID",
201
+	})
202
+	time.Sleep(statsdSleepTime)
203
+	suite.Contains(suite.statsdServer.String(),
204
+		"mtg.domain_fronting_connections:-1|g|#ip_family:ipv4")
205
+	suite.Contains(suite.statsdServer.String(),
206
+		"mtg.client_connections:-1|g|#ip_family:ipv4")
207
+
208
+	suite.NotContains(suite.statsdServer.String(), "telegram_traffic")
209
+	suite.NotContains(suite.statsdServer.String(), "telegram_connections")
155
 }
210
 }
156
 
211
 
157
 func (suite *StatsdTestSuite) TestEventConcurrencyLimited() {
212
 func (suite *StatsdTestSuite) TestEventConcurrencyLimited() {

+ 10
- 5
stats/stream_info.go View File

2
 
2
 
3
 import statsd "github.com/smira/go-statsd"
3
 import statsd "github.com/smira/go-statsd"
4
 
4
 
5
-type streamInfo map[string]string
5
+type streamInfo struct {
6
+	isDomainFronted bool
7
+	tags            map[string]string
8
+}
6
 
9
 
7
 func (s streamInfo) T(key string) statsd.Tag {
10
 func (s streamInfo) T(key string) statsd.Tag {
8
-	return statsd.StringTag(key, s[key])
11
+	return statsd.StringTag(key, s.tags[key])
9
 }
12
 }
10
 
13
 
11
-func (s streamInfo) Reset() {
12
-	for k := range s {
13
-		delete(s, k)
14
+func (s *streamInfo) Reset() {
15
+	s.isDomainFronted = false
16
+
17
+	for k := range s.tags {
18
+		delete(s.tags, k)
14
 	}
19
 	}
15
 }
20
 }
16
 
21
 

Loading…
Cancel
Save