|
16 | 16 |
|
17 | 17 | package io.cdap.plugin.batch.source; |
18 | 18 |
|
| 19 | +import com.google.common.base.Strings; |
| 20 | +import com.google.common.base.Throwables; |
| 21 | +import com.google.common.collect.ImmutableMap; |
| 22 | +import io.cdap.cdap.api.exception.ErrorCategory; |
| 23 | +import io.cdap.cdap.api.exception.ErrorType; |
| 24 | +import io.cdap.cdap.api.exception.ErrorUtils; |
| 25 | +import io.cdap.cdap.api.exception.ProgramFailureException; |
| 26 | +import io.cdap.cdap.api.metadata.MetadataException; |
| 27 | +import io.cdap.cdap.etl.api.exception.ErrorContext; |
19 | 28 | import io.cdap.plugin.common.HydratorErrorDetailsProvider; |
| 29 | +import org.apache.hadoop.fs.ChecksumException; |
| 30 | +import org.apache.hadoop.fs.FileAlreadyExistsException; |
| 31 | +import org.apache.hadoop.fs.InvalidPathException; |
| 32 | +import org.apache.hadoop.fs.InvalidRequestException; |
| 33 | +import org.apache.hadoop.fs.ParentNotDirectoryException; |
| 34 | +import org.apache.hadoop.fs.PathIsNotDirectoryException; |
| 35 | +import org.apache.hadoop.hdfs.BlockMissingException; |
| 36 | +import org.apache.hadoop.hdfs.protocol.QuotaExceededException; |
| 37 | +import org.apache.hadoop.hdfs.security.token.block.InvalidBlockTokenException; |
| 38 | +import org.apache.hadoop.hdfs.server.datanode.ReplicaNotFoundException; |
| 39 | +import org.apache.hadoop.hdfs.server.namenode.SafeModeException; |
| 40 | +import org.apache.hadoop.ipc.RemoteException; |
| 41 | +import org.apache.hadoop.ipc.StandbyException; |
| 42 | +import org.apache.hadoop.security.AccessControlException; |
| 43 | +import org.apache.hadoop.util.DiskChecker; |
| 44 | + |
| 45 | +import java.io.FileNotFoundException; |
| 46 | +import java.net.NoRouteToHostException; |
| 47 | +import java.net.SocketTimeoutException; |
| 48 | +import java.util.List; |
| 49 | +import java.util.Map; |
| 50 | +import java.util.concurrent.TimeoutException; |
| 51 | +import javax.annotation.Nullable; |
| 52 | +import javax.security.auth.login.FailedLoginException; |
20 | 53 |
|
21 | 54 | /** |
22 | 55 | * FileErrorDetails provider |
23 | 56 | */ |
24 | 57 | public class FileErrorDetailsProvider extends HydratorErrorDetailsProvider { |
25 | | - |
| 58 | + private static final String ERROR_MESSAGE_FORMAT = "Error occurred in the phase: '%s'. %s: %s"; |
| 59 | + |
| 60 | + private static final Map<Class<? extends Throwable>, ErrorType> exceptionErrorTypeMap = |
| 61 | + new ImmutableMap.Builder<Class<? extends Throwable>, ErrorType>() |
| 62 | + .put(FileNotFoundException.class, ErrorType.USER) |
| 63 | + .put(AccessControlException.class, ErrorType.USER) |
| 64 | + .put(ParentNotDirectoryException.class, ErrorType.USER) |
| 65 | + .put(InvalidPathException.class, ErrorType.USER) |
| 66 | + .put(FileAlreadyExistsException.class, ErrorType.USER) |
| 67 | + .put(QuotaExceededException.class, ErrorType.USER) |
| 68 | + .put(PathIsNotDirectoryException.class, ErrorType.USER) |
| 69 | + .put(InvalidRequestException.class, ErrorType.USER) |
| 70 | + .put(ChecksumException.class, ErrorType.USER) |
| 71 | + .put(RemoteException.class, ErrorType.SYSTEM) |
| 72 | + .put(SocketTimeoutException.class, ErrorType.SYSTEM) |
| 73 | + .put(DiskChecker.DiskOutOfSpaceException.class, ErrorType.SYSTEM) |
| 74 | + .put(StandbyException.class, ErrorType.SYSTEM) |
| 75 | + .put(NoRouteToHostException.class, ErrorType.SYSTEM) |
| 76 | + .put(BlockMissingException.class, ErrorType.SYSTEM) |
| 77 | + .put(ReplicaNotFoundException.class, ErrorType.SYSTEM) |
| 78 | + .put(InvalidBlockTokenException.class, ErrorType.SYSTEM) |
| 79 | + .put(SafeModeException.class, ErrorType.SYSTEM) |
| 80 | + .put(TimeoutException.class, ErrorType.SYSTEM) |
| 81 | + .put(FailedLoginException.class, ErrorType.SYSTEM) |
| 82 | + .put(MetadataException.class, ErrorType.SYSTEM) |
| 83 | + .build(); |
| 84 | + |
| 85 | + @Override |
| 86 | + public ProgramFailureException getExceptionDetails(Exception e, ErrorContext errorContext) { |
| 87 | + // Call super method to get base exception details |
| 88 | + ProgramFailureException ex = super.getExceptionDetails(e, errorContext); |
| 89 | + if (ex != null) { |
| 90 | + return ex; |
| 91 | + } |
| 92 | + return getFileBasedExceptionDetails(e, null, errorContext); |
| 93 | + } |
| 94 | + |
| 95 | + private static ProgramFailureException getFileBasedExceptionDetails(Exception e, @Nullable String errorReason, |
| 96 | + @Nullable ErrorContext errorContext) { |
| 97 | + List<Throwable> causalChain = Throwables.getCausalChain(e); |
| 98 | + |
| 99 | + for (Throwable t : causalChain) { |
| 100 | + for (Map.Entry<Class<? extends Throwable>, ErrorType> entry : exceptionErrorTypeMap.entrySet()) { |
| 101 | + if (entry.getKey().isInstance(t)) { |
| 102 | + return getProgramFailureException((Exception) t, errorContext, entry.getValue(), errorReason, true); |
| 103 | + } |
| 104 | + } |
| 105 | + } |
| 106 | + return null; |
| 107 | + } |
| 108 | + |
| 109 | + /** |
| 110 | + * Retrieves detailed exception information for file-based errors from an exception chain. |
| 111 | + * |
| 112 | + * @param e The Exception to get the error information from. |
| 113 | + * @return A ProgramFailureException with the given error information. |
| 114 | + */ |
| 115 | + public static ProgramFailureException getFileBasedProgramFailureExceptionDetailsFromChain(Exception e, |
| 116 | + @Nullable String errorReason) { |
| 117 | + ProgramFailureException ex = getFileBasedExceptionDetails(e, errorReason, null); |
| 118 | + if (ex == null) { |
| 119 | + return getProgramFailureException(e, null, ErrorType.UNKNOWN, errorReason, false); |
| 120 | + } |
| 121 | + return ex; |
| 122 | + } |
| 123 | + |
| 124 | + /** |
| 125 | + * Get a ProgramFailureException with the given error information from {@link Exception}. |
| 126 | + * |
| 127 | + * @param e The Exception to get the error information from. |
| 128 | + * @return A ProgramFailureException with the given error information. |
| 129 | + */ |
| 130 | + private static ProgramFailureException getProgramFailureException(Exception e, @Nullable ErrorContext errorContext, |
| 131 | + ErrorType errorType, @Nullable String errorReason, boolean dependency) { |
| 132 | + if (Strings.isNullOrEmpty(errorReason)) { |
| 133 | + errorReason = e.getMessage(); |
| 134 | + } |
| 135 | + String errorMessage = e.getMessage(); |
| 136 | + return ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN), |
| 137 | + errorReason, errorContext != null ? String.format(ERROR_MESSAGE_FORMAT, errorContext.getPhase(), e.getClass() |
| 138 | + .getName(), errorMessage) : String.format("%s: %s", e.getClass().getName(), errorMessage), errorType, dependency, e); |
| 139 | + } |
26 | 140 | } |
0 commit comments