1+ /**
2+ * Copyright 2020 Pinterest, Inc.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+ package com .pinterest .singer .writer ;
17+
18+ import java .util .Arrays ;
19+ import java .util .HashSet ;
20+ import java .util .Map ;
21+ import java .util .Map .Entry ;
22+ import java .util .Set ;
23+
24+ import org .apache .kafka .clients .producer .KafkaProducer ;
25+ import org .apache .kafka .common .Metric ;
26+ import org .apache .kafka .common .MetricName ;
27+ import org .slf4j .Logger ;
28+ import org .slf4j .LoggerFactory ;
29+
30+ import com .pinterest .singer .metrics .OpenTsdbMetricConverter ;
31+ import com .pinterest .singer .thrift .configuration .KafkaProducerConfig ;
32+ import com .pinterest .singer .utils .LogConfigUtils ;
33+
34+ /**
35+ * Responsible for pulling metrics from {@link KafkaProducer} and copying them
36+ * to Ostrich so they can be accessed and forwarded. This helps provide
37+ * additional instrumentation on Singer and how it's performing.
38+ */
39+ public class KafkaProducerMetricsMonitor implements Runnable {
40+
41+ private static final Logger LOG = LoggerFactory .getLogger (KafkaProducerMetricsMonitor .class );
42+ public static final Set <String > PRODUCER_METRICS_WHITELIST = new HashSet <>(
43+ Arrays .asList ("buffer-total-bytes" , "buffer-available-bytes" ));
44+ // sample every 60seconds
45+ private static final int SAMPLING_INTERVAL = 60_000 ;
46+
47+ @ Override
48+ public void run () {
49+ while (true ) {
50+ try {
51+ publishKafkaProducerMetricsToOstrich ();
52+ } catch (Exception e ) {
53+ LOG .warn ("Error publishing KafkaProducer metrics" , e );
54+ }
55+ try {
56+ Thread .sleep (SAMPLING_INTERVAL );
57+ } catch (InterruptedException e ) {
58+ LOG .warn ("KafkaProducerMetricsMonitor thread interrupted, exiting" );
59+ break ;
60+ }
61+ }
62+ }
63+
64+ @ SuppressWarnings ({ "deprecation" })
65+ protected void publishKafkaProducerMetricsToOstrich () {
66+ Map <KafkaProducerConfig , KafkaProducer <byte [], byte []>> producers = KafkaProducerManager
67+ .getInstance ().getProducers ();
68+ for (Entry <KafkaProducerConfig , KafkaProducer <byte [], byte []>> kafkaProducerEntry : producers
69+ .entrySet ()) {
70+ KafkaProducerConfig key = kafkaProducerEntry .getKey ();
71+ String signature = convertSignatureToTag (key );
72+ Map <MetricName , ? extends Metric > metrics = kafkaProducerEntry .getValue ().metrics ();
73+ for (Entry <MetricName , ? extends Metric > entry : metrics .entrySet ()) {
74+ if (PRODUCER_METRICS_WHITELIST .contains (entry .getKey ().name ())) {
75+ OpenTsdbMetricConverter .gauge ("kafkaproducer." + entry .getKey ().name (),
76+ entry .getValue ().value (), "cluster=" + signature );
77+ }
78+ }
79+ }
80+ }
81+
82+ public static String convertSignatureToTag (KafkaProducerConfig key ) {
83+ return key .getKafkaClusterSignature ()
84+ .replaceAll ("(" + LogConfigUtils .DEFAULT_SERVERSET_DIR + "|discovery|/|prod|\\ .)" , "" );
85+ }
86+
87+ }
0 commit comments