24
24
import io .cdap .cdap .api .annotation .Plugin ;
25
25
import io .cdap .cdap .api .data .format .StructuredRecord ;
26
26
import io .cdap .cdap .api .data .schema .Schema ;
27
+ import io .cdap .cdap .api .exception .ErrorType ;
27
28
import io .cdap .cdap .api .metrics .Metrics ;
28
29
import io .cdap .cdap .api .plugin .PluginConfig ;
29
30
import io .cdap .cdap .api .plugin .PluginProperties ;
53
54
import io .cdap .wrangler .api .EntityCountMetric ;
54
55
import io .cdap .wrangler .api .ErrorRecord ;
55
56
import io .cdap .wrangler .api .ExecutorContext ;
57
+ import io .cdap .wrangler .api .RecipeException ;
56
58
import io .cdap .wrangler .api .RecipeParser ;
57
59
import io .cdap .wrangler .api .RecipePipeline ;
58
60
import io .cdap .wrangler .api .RecipeSymbol ;
@@ -243,9 +245,13 @@ public void configurePipeline(PipelineConfigurer configurer) {
243
245
}
244
246
}
245
247
} catch (CompileException e ) {
246
- collector .addFailure ("Compilation error occurred : " + e .getMessage (), null );
248
+ collector .addFailure (
249
+ String .format ("Compilation error occurred, %s: %s " , e .getClass ().getName (),
250
+ e .getMessage ()), null );
247
251
} catch (DirectiveParseException e ) {
248
- collector .addFailure (e .getMessage (), null );
252
+ collector .addFailure (
253
+ String .format ("Error parsing directive, %s: %s" , e .getClass ().getName (),
254
+ e .getMessage ()), null );
249
255
}
250
256
251
257
// Based on the configuration create output schema.
@@ -254,8 +260,9 @@ public void configurePipeline(PipelineConfigurer configurer) {
254
260
oSchema = Schema .parseJson (config .schema );
255
261
}
256
262
} catch (IOException e ) {
257
- collector .addFailure ("Invalid output schema." , null )
258
- .withConfigProperty (Config .NAME_SCHEMA ).withStacktrace (e .getStackTrace ());
263
+ collector .addFailure (
264
+ String .format ("Invalid output schema %s: %s" , e .getClass ().getName (), e .getMessage ()),
265
+ null ).withConfigProperty (Config .NAME_SCHEMA ).withStacktrace (e .getStackTrace ());
259
266
}
260
267
261
268
// Check if jexl pre-condition is not null or empty and if so compile expression.
@@ -265,7 +272,9 @@ && checkPreconditionNotEmpty(false)) {
265
272
try {
266
273
new Precondition (config .getPreconditionJEXL ());
267
274
} catch (PreconditionException e ) {
268
- collector .addFailure (e .getMessage (), null ).withConfigProperty (Config .NAME_PRECONDITION );
275
+ collector .addFailure (String .format ("Error compiling precondition expression, %s: %s" ,
276
+ e .getClass ().getName (), e .getMessage ()), null )
277
+ .withConfigProperty (Config .NAME_PRECONDITION );
269
278
}
270
279
}
271
280
}
@@ -276,8 +285,11 @@ && checkPreconditionNotEmpty(false)) {
276
285
}
277
286
278
287
} catch (Exception e ) {
279
- LOG .error (e .getMessage ());
280
- collector .addFailure ("Error occurred : " + e .getMessage (), null ).withStacktrace (e .getStackTrace ());
288
+ LOG .error ("Error occurred during configuration of the plugin, {}: {}" , e .getClass ().getName (),
289
+ e .getMessage ());
290
+ collector .addFailure (
291
+ String .format ("Error occurred during configuration of the plugin, %s: %s" ,
292
+ e .getClass ().getName (), e .getMessage ()), null ).withStacktrace (e .getStackTrace ());
281
293
}
282
294
}
283
295
@@ -319,7 +331,12 @@ public void prepareRun(StageSubmitterContext context) throws Exception {
319
331
// Parse the recipe and extract all the instances of directives
320
332
// to be processed for extracting lineage.
321
333
RecipeParser recipe = getRecipeParser (context );
322
- List <Directive > directives = recipe .parse ();
334
+ List <Directive > directives ;
335
+ try {
336
+ directives = recipe .parse ();
337
+ } catch (RecipeException e ) {
338
+ throw WranglerUtil .getProgramFailureExceptionDetailsFromChain (e , null , ErrorType .SYSTEM , false );
339
+ }
323
340
emitDirectiveMetrics (directives , context .getMetrics ());
324
341
325
342
LineageOperations lineageOperations = new LineageOperations (input , output , directives );
@@ -345,10 +362,11 @@ public void initialize(TransformContext context) throws Exception {
345
362
try {
346
363
oSchema = Schema .parseJson (config .schema );
347
364
} catch (IOException e ) {
348
- throw new IllegalArgumentException (
349
- String .format ("Stage:%s - Format of output schema specified is invalid. Please check the format." ,
350
- context .getStageName ()), e
351
- );
365
+ String errorMessage = String .format ("Error in stage '%s'. Format of output schema specified "
366
+ + "is invalid. Please check the format. %s: %s" , context .getStageName (),
367
+ e .getClass ().getName (), e .getMessage ());
368
+ throw WranglerUtil .getProgramFailureExceptionDetailsFromChain (
369
+ new IllegalArgumentException (errorMessage , e ), errorMessage , ErrorType .USER , false );
352
370
}
353
371
354
372
// Check if jexl pre-condition is not null or empty and if so compile expression.
@@ -358,7 +376,7 @@ && checkPreconditionNotEmpty(false)) {
358
376
try {
359
377
condition = new Precondition (config .getPreconditionJEXL ());
360
378
} catch (PreconditionException e ) {
361
- throw new IllegalArgumentException ( e . getMessage (), e );
379
+ throw WranglerUtil . getProgramFailureExceptionDetailsFromChain ( e , null , ErrorType . SYSTEM , false );
362
380
}
363
381
}
364
382
}
@@ -367,7 +385,11 @@ && checkPreconditionNotEmpty(false)) {
367
385
// Create the pipeline executor with context being set.
368
386
pipeline = new RecipePipelineExecutor (recipe , ctx );
369
387
} catch (Exception e ) {
370
- throw new Exception (String .format ("Stage:%s - %s" , getContext ().getStageName (), e .getMessage ()), e );
388
+ String errorMessage = String .format (
389
+ "Error in stage '%s'. Please check the configuration or input data. %s: %s" ,
390
+ context .getStageName (), e .getClass ().getName (), e .getMessage ());
391
+ throw WranglerUtil .getProgramFailureExceptionDetailsFromChain (e , errorMessage ,
392
+ ErrorType .SYSTEM , false );
371
393
}
372
394
373
395
String defaultStrategy = context .getArguments ().get (ERROR_STRATEGY_DEFAULT );
@@ -437,8 +459,10 @@ && checkPreconditionNotEmpty(false)) {
437
459
}
438
460
if (WRANGLER_FAIL_PIPELINE_FOR_ERROR .isEnabled (getContext ())
439
461
&& onErrorStrategy .equalsIgnoreCase (ON_ERROR_FAIL_PIPELINE )) {
440
- throw new Exception (
441
- String .format ("Errors in Wrangler Transformation - %s" , errorMessages ));
462
+ String errorReason = String .format ("Errors in Wrangler Transformation - %s" ,
463
+ errorMessages );
464
+ throw WranglerUtil .getProgramFailureExceptionDetailsFromChain (null , errorReason ,
465
+ ErrorType .SYSTEM , true );
442
466
}
443
467
}
444
468
} catch (Exception e ) {
@@ -457,8 +481,10 @@ && checkPreconditionNotEmpty(false)) {
457
481
getContext ().getStageName (), e .getMessage ()),
458
482
"value" , String .valueOf (errorCounter )
459
483
));
460
- throw new Exception (String .format ("Stage:%s - Failing pipeline due to error : %s" ,
461
- getContext ().getStageName (), e .getMessage ()), e );
484
+ String errorMessage = String .format ("Pipeline failed at stage:%s, %s: %s" ,
485
+ getContext ().getStageName (), e .getClass ().getName (), e .getMessage ());
486
+ throw WranglerUtil .getProgramFailureExceptionDetailsFromChain (e , errorMessage ,
487
+ ErrorType .SYSTEM , true );
462
488
}
463
489
// If it's 'skip-on-error' we continue processing and don't emit any error records.
464
490
return ;
@@ -553,18 +579,32 @@ private boolean checkPreconditionNotEmpty(Boolean isConditionSQL) {
553
579
* @throws DirectiveLoadException
554
580
* @throws DirectiveParseException
555
581
*/
556
- private RecipeParser getRecipeParser (StageContext context )
557
- throws DirectiveLoadException , DirectiveParseException {
582
+ private RecipeParser getRecipeParser (StageContext context ) {
558
583
559
584
registry = new CompositeDirectiveRegistry (SystemDirectiveRegistry .INSTANCE , new UserDirectiveRegistry (context ));
560
- registry .reload (context .getNamespace ());
585
+ try {
586
+ registry .reload (context .getNamespace ());
587
+ } catch (DirectiveLoadException e ) {
588
+ LOG .error ("Failed to reload the directive registry for namespace "
589
+ + "'{}' at stage '{}'. Please verify the namespace and ensure the directives are "
590
+ + "correctly configured. {}: {}" , context .getNamespace (), context .getStageName (),
591
+ e .getClass ().getName (), e .getMessage ());
592
+ throw WranglerUtil .getProgramFailureExceptionDetailsFromChain (e , null , ErrorType .USER , false );
593
+ }
561
594
562
595
String directives = config .getDirectives ();
563
596
if (config .getUDDs () != null && !config .getUDDs ().trim ().isEmpty ()) {
564
597
directives = String .format ("#pragma load-directives %s;%s" , config .getUDDs (), config .getDirectives ());
565
598
}
566
599
567
- return new GrammarBasedParser (context .getNamespace (), new MigrateToV2 (directives ).migrate (), registry );
600
+ try {
601
+ return new GrammarBasedParser (context .getNamespace (), new MigrateToV2 (directives ).migrate (), registry );
602
+ } catch (DirectiveParseException e ) {
603
+ LOG .error ("Failed to parse directives for namespace '{}' at stage "
604
+ + "'{}'. Please verify the directives and ensure they are correctly formatted. {}, {}" ,
605
+ context .getNamespace (), context .getStageName (), e .getClass ().getName (), e .getMessage ());
606
+ throw WranglerUtil .getProgramFailureExceptionDetailsFromChain (e , null , ErrorType .USER , false );
607
+ }
568
608
}
569
609
570
610
@ Override
@@ -573,7 +613,8 @@ public Relation transform(RelationalTranformContext relationalTranformContext, R
573
613
&& checkPreconditionNotEmpty (true )) {
574
614
575
615
if (!Feature .WRANGLER_PRECONDITION_SQL .isEnabled (relationalTranformContext )) {
576
- throw new RuntimeException ("SQL Precondition feature is not available" );
616
+ throw WranglerUtil .getProgramFailureExceptionDetailsFromChain (null ,
617
+ "SQL Precondition feature is not available" , ErrorType .SYSTEM , true );
577
618
}
578
619
579
620
Optional <ExpressionFactory <String >> expressionFactory = getExpressionFactory (relationalTranformContext );
@@ -598,11 +639,18 @@ private Optional<ExpressionFactory<String>> getExpressionFactory(RelationalTranf
598
639
* @param directives a list of Wrangler directives
599
640
* @param metrics CDAP {@link Metrics} object using which metrics can be emitted
600
641
*/
601
- private void emitDirectiveMetrics (List <Directive > directives , Metrics metrics ) throws DirectiveLoadException {
642
+ private void emitDirectiveMetrics (List <Directive > directives , Metrics metrics ) {
602
643
for (Directive directive : directives ) {
603
644
// skip emitting metrics if the directive is not system directive
604
- if (registry .get (Contexts .SYSTEM , directive .define ().getDirectiveName ()) == null ) {
605
- continue ;
645
+ try {
646
+ if (registry .get (Contexts .SYSTEM , directive .define ().getDirectiveName ()) == null ) {
647
+ continue ;
648
+ }
649
+ } catch (DirectiveLoadException e ) {
650
+ LOG .error ("Error loading system directive '{}'. {}: {}" ,
651
+ directive .define ().getDirectiveName (), e .getClass ().getName (), e .getMessage ());
652
+ throw WranglerUtil .getProgramFailureExceptionDetailsFromChain (e , null , ErrorType .SYSTEM ,
653
+ false );
606
654
}
607
655
List <EntityCountMetric > countMetrics = new ArrayList <>();
608
656
0 commit comments