@@ -3,15 +3,19 @@ package main
3
3
import (
4
4
"context"
5
5
"crypto/rand"
6
+ "crypto/x509"
6
7
"flag"
7
8
"fmt"
8
9
"io"
10
+ "io/ioutil"
11
+ "log"
9
12
"os"
10
13
"strings"
11
14
gosync "sync"
12
15
"time"
13
16
14
17
"github.com/Shopify/sarama"
18
+ "github.com/Shopify/sarama/tools/tls"
15
19
metrics "github.com/rcrowley/go-metrics"
16
20
)
17
21
36
40
"" ,
37
41
"REQUIRED: A comma separated list of broker addresses." ,
38
42
)
43
+ securityProtocol = flag .String (
44
+ "security-protocol" ,
45
+ "PLAINTEXT" ,
46
+ "The name of the security protocol to talk to Kafka (PLAINTEXT, SSL) (default: PLAINTEXT)." ,
47
+ )
48
+ tlsRootCACerts = flag .String (
49
+ "tls-ca-certs" ,
50
+ "" ,
51
+ "The path to a file that contains a set of root certificate authorities in PEM format " +
52
+ "to trust when verifying broker certificates when -security-protocol=SSL " +
53
+ "(leave empty to use the host's root CA set)." ,
54
+ )
55
+ tlsClientCert = flag .String (
56
+ "tls-client-cert" ,
57
+ "" ,
58
+ "The path to a file that contains the client certificate to send to the broker " +
59
+ "in PEM format if client authentication is required when -security-protocol=SSL " +
60
+ "(leave empty to disable client authentication)." ,
61
+ )
62
+ tlsClientKey = flag .String (
63
+ "tls-client-key" ,
64
+ "" ,
65
+ "The path to a file that contains the client private key linked to the client certificate " +
66
+ "in PEM format when -security-protocol=SSL (REQUIRED if tls-client-cert is provided)." ,
67
+ )
39
68
topic = flag .String (
40
69
"topic" ,
41
70
"" ,
@@ -126,6 +155,11 @@ var (
126
155
"0.8.2.0" ,
127
156
"The assumed version of Kafka." ,
128
157
)
158
+ verbose = flag .Bool (
159
+ "verbose" ,
160
+ false ,
161
+ "Turn on sarama logging to stderr" ,
162
+ )
129
163
)
130
164
131
165
func parseCompression (scheme string ) sarama.CompressionCodec {
@@ -205,6 +239,12 @@ func main() {
205
239
if * routines < 1 || * routines > * messageLoad {
206
240
printUsageErrorAndExit ("-routines must be greater than 0 and less than or equal to -message-load" )
207
241
}
242
+ if * securityProtocol != "PLAINTEXT" && * securityProtocol != "SSL" {
243
+ printUsageErrorAndExit (fmt .Sprintf ("-security-protocol %q is not supported" , * securityProtocol ))
244
+ }
245
+ if * verbose {
246
+ sarama .Logger = log .New (os .Stderr , "" , log .LstdFlags )
247
+ }
208
248
209
249
config := sarama .NewConfig ()
210
250
@@ -222,6 +262,30 @@ func main() {
222
262
config .ChannelBufferSize = * channelBufferSize
223
263
config .Version = parseVersion (* version )
224
264
265
+ if * securityProtocol == "SSL" {
266
+ tlsConfig , err := tls .NewConfig (* tlsClientCert , * tlsClientKey )
267
+ if err != nil {
268
+ printErrorAndExit (69 , "failed to load client certificate from: %s and private key from: %s: %v" ,
269
+ * tlsClientCert , * tlsClientKey , err )
270
+ }
271
+
272
+ if * tlsRootCACerts != "" {
273
+ rootCAsBytes , err := ioutil .ReadFile (* tlsRootCACerts )
274
+ if err != nil {
275
+ printErrorAndExit (69 , "failed to read root CA certificates: %v" , err )
276
+ }
277
+ certPool := x509 .NewCertPool ()
278
+ if ! certPool .AppendCertsFromPEM (rootCAsBytes ) {
279
+ printErrorAndExit (69 , "failed to load root CA certificates from file: %s" , * tlsRootCACerts )
280
+ }
281
+ // Use specific root CA set vs the host's set
282
+ tlsConfig .RootCAs = certPool
283
+ }
284
+
285
+ config .Net .TLS .Enable = true
286
+ config .Net .TLS .Config = tlsConfig
287
+ }
288
+
225
289
if err := config .Validate (); err != nil {
226
290
printErrorAndExit (69 , "Invalid configuration: %s" , err )
227
291
}
@@ -363,18 +427,24 @@ func runSyncProducer(topic string, partition, messageLoad, messageSize, routines
363
427
}
364
428
365
429
func printMetrics (w io.Writer , r metrics.Registry ) {
366
- if r .Get ("record-send-rate" ) == nil || r .Get ("request-latency-in-ms" ) == nil {
430
+ recordSendRateMetric := r .Get ("record-send-rate" )
431
+ requestLatencyMetric := r .Get ("request-latency-in-ms" )
432
+ outgoingByteRateMetric := r .Get ("outgoing-byte-rate" )
433
+
434
+ if recordSendRateMetric == nil || requestLatencyMetric == nil || outgoingByteRateMetric == nil {
367
435
return
368
436
}
369
- recordSendRate := r . Get ( "record-send-rate" ) .(metrics.Meter ).Snapshot ()
370
- requestLatency := r . Get ( "request-latency-in-ms" ) .(metrics.Histogram ).Snapshot ()
437
+ recordSendRate := recordSendRateMetric .(metrics.Meter ).Snapshot ()
438
+ requestLatency := requestLatencyMetric .(metrics.Histogram ).Snapshot ()
371
439
requestLatencyPercentiles := requestLatency .Percentiles ([]float64 {0.5 , 0.75 , 0.95 , 0.99 , 0.999 })
372
- fmt .Fprintf (w , "%d records sent, %.1f records/sec (%.2f MB/sec), " +
440
+ outgoingByteRate := outgoingByteRateMetric .(metrics.Meter ).Snapshot ()
441
+ fmt .Fprintf (w , "%d records sent, %.1f records/sec (%.2f MiB/sec ingress, %.2f MiB/sec egress), " +
373
442
"%.1f ms avg latency, %.1f ms stddev, %.1f ms 50th, %.1f ms 75th, " +
374
443
"%.1f ms 95th, %.1f ms 99th, %.1f ms 99.9th\n " ,
375
444
recordSendRate .Count (),
376
445
recordSendRate .RateMean (),
377
446
recordSendRate .RateMean ()* float64 (* messageSize )/ 1024 / 1024 ,
447
+ outgoingByteRate .RateMean ()/ 1024 / 1024 ,
378
448
requestLatency .Mean (),
379
449
requestLatency .StdDev (),
380
450
requestLatencyPercentiles [0 ],
0 commit comments