@@ -242,6 +242,87 @@ static List<UserScramCredentialAlteration> ParseUserScramCredentialAlterations(
242
242
return alterations ;
243
243
}
244
244
245
+ static Tuple < IsolationLevel , List < TopicPartitionOffsetSpec > > ParseListOffsetsArgs ( string [ ] args )
246
+ {
247
+ if ( args . Length == 0 )
248
+ {
249
+ Console . WriteLine ( "usage: .. <bootstrapServers> list-offsets <isolation_level> " +
250
+ "<topic1> <partition1> <EARLIEST/LATEST/MAXTIMESTAMP/TIMESTAMP t1> .." ) ;
251
+ Environment . ExitCode = 1 ;
252
+ return null ;
253
+ }
254
+
255
+ var isolationLevel = Enum . Parse < IsolationLevel > ( args [ 0 ] ) ;
256
+ var topicPartitionOffsetSpecs = new List < TopicPartitionOffsetSpec > ( ) ;
257
+ for ( int i = 1 ; i < args . Length ; )
258
+ {
259
+ if ( args . Length < i + 3 )
260
+ {
261
+ throw new ArgumentException ( $ "Invalid number of arguments for topicPartitionOffsetSpec[{ topicPartitionOffsetSpecs . Count } ]: { args . Length - i } ") ;
262
+ }
263
+
264
+ string topic = args [ i ] ;
265
+ var partition = Int32 . Parse ( args [ i + 1 ] ) ;
266
+ var offsetSpec = args [ i + 2 ] ;
267
+ if ( offsetSpec == "TIMESTAMP" )
268
+ {
269
+ if ( args . Length < i + 4 )
270
+ {
271
+ throw new ArgumentException ( $ "Invalid number of arguments for topicPartitionOffsetSpec[{ topicPartitionOffsetSpecs . Count } ]: { args . Length - i } ") ;
272
+ }
273
+
274
+ var timestamp = Int64 . Parse ( args [ i + 3 ] ) ;
275
+ i = i + 1 ;
276
+ topicPartitionOffsetSpecs . Add ( new TopicPartitionOffsetSpec
277
+ {
278
+ TopicPartition = new TopicPartition ( topic , new Partition ( partition ) ) ,
279
+ OffsetSpec = OffsetSpec . ForTimestamp ( timestamp )
280
+ } ) ;
281
+ }
282
+ else if ( offsetSpec == "MAX_TIMESTAMP" )
283
+ {
284
+ topicPartitionOffsetSpecs . Add ( new TopicPartitionOffsetSpec
285
+ {
286
+ TopicPartition = new TopicPartition ( topic , new Partition ( partition ) ) ,
287
+ OffsetSpec = OffsetSpec . MaxTimestamp ( )
288
+ } ) ;
289
+ }
290
+ else if ( offsetSpec == "EARLIEST" )
291
+ {
292
+ topicPartitionOffsetSpecs . Add ( new TopicPartitionOffsetSpec
293
+ {
294
+ TopicPartition = new TopicPartition ( topic , new Partition ( partition ) ) ,
295
+ OffsetSpec = OffsetSpec . Earliest ( )
296
+ } ) ;
297
+ }
298
+ else if ( offsetSpec == "LATEST" )
299
+ {
300
+ topicPartitionOffsetSpecs . Add ( new TopicPartitionOffsetSpec
301
+ {
302
+ TopicPartition = new TopicPartition ( topic , new Partition ( partition ) ) ,
303
+ OffsetSpec = OffsetSpec . Latest ( )
304
+ } ) ;
305
+ }
306
+ else
307
+ {
308
+ throw new ArgumentException (
309
+ "offsetSpec can be EARLIEST, LATEST, MAX_TIMESTAMP or TIMESTAMP T1." ) ;
310
+ }
311
+ i = i + 3 ;
312
+ }
313
+ return Tuple . Create ( isolationLevel , topicPartitionOffsetSpecs ) ;
314
+ }
315
+
316
+ static void PrintListOffsetsResultInfos ( List < ListOffsetsResultInfo > ListOffsetsResultInfos )
317
+ {
318
+ foreach ( var listOffsetsResultInfo in ListOffsetsResultInfos )
319
+ {
320
+ Console . WriteLine ( " ListOffsetsResultInfo:" ) ;
321
+ Console . WriteLine ( $ " TopicPartitionOffsetError: { listOffsetsResultInfo . TopicPartitionOffsetError } ") ;
322
+ Console . WriteLine ( $ " Timestamp: { listOffsetsResultInfo . Timestamp } ") ;
323
+ }
324
+ }
325
+
245
326
static async Task CreateAclsAsync ( string bootstrapServers , string [ ] commandArgs )
246
327
{
247
328
List < AclBinding > aclBindings ;
@@ -793,6 +874,38 @@ await adminClient.AlterUserScramCredentialsAsync(alterations,
793
874
}
794
875
}
795
876
877
+ static async Task ListOffsetsAsync ( string bootstrapServers , string [ ] commandArgs ) {
878
+
879
+ var listOffsetsArgs = ParseListOffsetsArgs ( commandArgs ) ;
880
+ if ( listOffsetsArgs == null ) { return ; }
881
+
882
+ var isolationLevel = listOffsetsArgs . Item1 ;
883
+ var topicPartitionOffsets = listOffsetsArgs . Item2 ;
884
+
885
+ var timeout = TimeSpan . FromSeconds ( 30 ) ;
886
+ ListOffsetsOptions options = new ListOffsetsOptions ( ) { RequestTimeout = timeout , IsolationLevel = isolationLevel } ;
887
+
888
+ using ( var adminClient = new AdminClientBuilder ( new AdminClientConfig { BootstrapServers = bootstrapServers } ) . Build ( ) )
889
+ {
890
+ try
891
+ {
892
+ var listOffsetsResult = await adminClient . ListOffsetsAsync ( topicPartitionOffsets , options ) ;
893
+ Console . WriteLine ( "ListOffsetsResult:" ) ;
894
+ PrintListOffsetsResultInfos ( listOffsetsResult . ListOffsetsResultInfos ) ;
895
+ }
896
+ catch ( ListOffsetsException e )
897
+ {
898
+ Console . WriteLine ( "ListOffsetsReport:" ) ;
899
+ Console . WriteLine ( $ " Error: { e . Error } ") ;
900
+ PrintListOffsetsResultInfos ( e . Result . ListOffsetsResultInfos ) ;
901
+ }
902
+ catch ( KafkaException e )
903
+ {
904
+ Console . WriteLine ( $ "An error occurred listing offsets: { e } ") ;
905
+ Environment . ExitCode = 1 ;
906
+ }
907
+ }
908
+ }
796
909
static void PrintTopicDescriptions ( List < TopicDescription > topicDescriptions , bool includeAuthorizedOperations )
797
910
{
798
911
foreach ( var topic in topicDescriptions )
@@ -956,12 +1069,11 @@ public static async Task Main(string[] args)
956
1069
Console . WriteLine (
957
1070
"usage: .. <bootstrapServers> " + String . Join ( "|" , new string [ ] {
958
1071
"list-groups" , "metadata" , "library-version" , "create-topic" , "create-acls" ,
959
- "describe-acls" , "delete-acls" ,
960
1072
"list-consumer-groups" , "describe-consumer-groups" ,
961
1073
"list-consumer-group-offsets" , "alter-consumer-group-offsets" ,
962
1074
"incremental-alter-configs" , "describe-user-scram-credentials" ,
963
1075
"alter-user-scram-credentials" , "describe-topics" ,
964
- "describe-cluster"
1076
+ "describe-cluster" , "list-offsets"
965
1077
} ) +
966
1078
" .." ) ;
967
1079
Environment . ExitCode = 1 ;
@@ -1022,6 +1134,9 @@ public static async Task Main(string[] args)
1022
1134
case "describe-cluster" :
1023
1135
await DescribeClusterAsync ( bootstrapServers , commandArgs ) ;
1024
1136
break ;
1137
+ case "list-offsets" :
1138
+ await ListOffsetsAsync ( bootstrapServers , commandArgs ) ;
1139
+ break ;
1025
1140
default :
1026
1141
Console . WriteLine ( $ "unknown command: { command } ") ;
1027
1142
break ;
0 commit comments