001 /* 002 * Copyright (c) 2007-2015 Concurrent, Inc. All Rights Reserved. 003 * 004 * Project and contact information: http://www.cascading.org/ 005 * 006 * This file is part of the Cascading project. 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020 021 package cascading.tap; 022 023 import java.util.Properties; 024 025 import cascading.property.Props; 026 027 /** 028 * Class TrapProps is a fluent helper class to set properties which control the behaviour of {@link cascading.tap.Tap} 029 * instances used as traps on a given {@link cascading.flow.Flow}. 030 * <p/> 031 * A Tap trap is used to capture bad data that has triggered an unhandled {@link java.lang.Throwable} within a 032 * Cascading {@link cascading.operation.Operation} or {@link cascading.tap.Tap} (either as a source or sink). 033 * <p/> 034 * When a trap captures a failure, the {@link cascading.tuple.Tuple} arguments to the Operation or Tap will be 035 * captured and the Flow will continue executing with the next Tuple in the stream. Otherwise a Flow would 036 * typically fail. 037 * <p/> 038 * Due to the variability of data in the stream at any given point, a Tap trap should be configured with a 039 * {@link cascading.scheme.Scheme} that sinks {@link cascading.tuple.Fields#ALL}, or is guaranteed to sink known 040 * fields common to all Operations within the branch the trap has been bound too. 041 * <p/> 042 * Optionally diagnostic information, with the given field names, may be captured along with the argument Tuple. 043 * <p/> 044 * <ul> 045 * <li>{@code element-trace} - the file and line number the failed operation was instantiated</li> 046 * <li>{@code throwable-message} - the {@link Throwable#getMessage()} value</li> 047 * <li>{@code throwable-stacktrace} - the {@link Throwable#printStackTrace()} value, cleansed</li> 048 * </ul> 049 * <p/> 050 * By default, if the Throwable stacktrace is captured, each line of the trace will be trimmed (to remove the 051 * TAB character ({@code \t}) and each new line ({@code \n}) will be replaced with a pipe character ({@code |}). 052 * <p/> 053 * Each value is prepended to the argument Tuple in the order given above. Since the argument Tuple may vary 054 * in size, prepending the diagnostic value deterministically allows for simple grep and sed like commands to be 055 * applied to the files. 056 * <p/> 057 * Trap properties can be applied to a given Flow by calling {@link #buildProperties()} on the properties instance 058 * handed to the target {@link cascading.flow.FlowConnector} or directly to any given Tap via the 059 * {@link Tap#getConfigDef()} using {@link #setProperties(cascading.property.ConfigDef)}. 060 * <p/> 061 * It should be noted that traps are not intended for 'flow control' of a data stream. They are for exceptional 062 * cases that when reached should not cause a Flow to fail. Flow control (sending known bad data down a different 063 * branch) should be part of the application. Traps capture the values that are unaccounted for and cause errors, 064 * if missing them doesn't compromise the integrity of the application. 065 */ 066 public class TrapProps extends Props 067 { 068 public static final String RECORD_ELEMENT_TRACE = "cascading.trap.elementtrace.record"; 069 public static final String RECORD_THROWABLE_MESSAGE = "cascading.trap.throwable.message.record"; 070 public static final String RECORD_THROWABLE_STACK_TRACE = "cascading.trap.throwable.stacktrace.record"; 071 public static final String LOG_THROWABLE_STACK_TRACE = "cascading.trap.throwable.stacktrace.log"; 072 public static final String STACK_TRACE_LINE_TRIM = "cascading.trap.throwable.stacktrace.line.trim"; 073 public static final String STACK_TRACE_LINE_DELIMITER = "cascading.trap.throwable.stacktrace.line.delimiter"; 074 075 protected boolean recordElementTrace = false; 076 protected boolean recordThrowableMessage = false; 077 protected boolean recordThrowableStackTrace = false; 078 079 protected boolean logThrowableStackTrace = true; 080 081 protected boolean stackTraceTrimLine = true; 082 protected String stackTraceLineDelimiter = null; 083 084 public static TrapProps trapProps() 085 { 086 return new TrapProps(); 087 } 088 089 public TrapProps() 090 { 091 } 092 093 /** 094 * Method recordAllDiagnostics enables recording of all configurable diagnostic values. 095 * 096 * @return this 097 */ 098 public TrapProps recordAllDiagnostics() 099 { 100 recordElementTrace = true; 101 recordThrowableMessage = true; 102 recordThrowableStackTrace = true; 103 104 return this; 105 } 106 107 public boolean isRecordElementTrace() 108 { 109 return recordElementTrace; 110 } 111 112 /** 113 * Method setRecordElementTrace will enable recording the element trace value if set to {@code true}. 114 * <p/> 115 * The default is {@code false}. 116 * 117 * @param recordElementTrace of type boolean 118 * @return this 119 */ 120 public TrapProps setRecordElementTrace( boolean recordElementTrace ) 121 { 122 this.recordElementTrace = recordElementTrace; 123 124 return this; 125 } 126 127 public boolean isRecordThrowableMessage() 128 { 129 return recordThrowableMessage; 130 } 131 132 /** 133 * Method setRecordThrowableMessage will enable recording the Throwable message value if set to {@code true}. 134 * <p/> 135 * The default is {@code false}. 136 * 137 * @param recordThrowableMessage of type boolean 138 * @return this 139 */ 140 public TrapProps setRecordThrowableMessage( boolean recordThrowableMessage ) 141 { 142 this.recordThrowableMessage = recordThrowableMessage; 143 144 return this; 145 } 146 147 public boolean isRecordThrowableStackTrace() 148 { 149 return recordThrowableStackTrace; 150 } 151 152 /** 153 * Method setRecordThrowableStackTrace will enable recording the Throwable stacktrace value if set to {@code true}. 154 * <p/> 155 * The default is {@code false}. 156 * 157 * @param recordThrowableStackTrace of type boolean 158 * @return this 159 */ 160 public TrapProps setRecordThrowableStackTrace( boolean recordThrowableStackTrace ) 161 { 162 this.recordThrowableStackTrace = recordThrowableStackTrace; 163 164 return this; 165 } 166 167 public boolean isLogThrowableStackTrace() 168 { 169 return logThrowableStackTrace; 170 } 171 172 /** 173 * Method setLogThrowableStackTrace will disable logging of the Throwable stacktrace value if set to {@code false}. 174 * <p/> 175 * The default is {@code true}. 176 * 177 * @param logThrowableStackTrace of type boolean 178 * @return this 179 */ 180 public TrapProps setLogThrowableStackTrace( boolean logThrowableStackTrace ) 181 { 182 this.logThrowableStackTrace = logThrowableStackTrace; 183 184 return this; 185 } 186 187 public boolean isStackTraceTrimLine() 188 { 189 return stackTraceTrimLine; 190 } 191 192 /** 193 * Method setStackTraceTrimLine will disable trimming of whitespace on every recorded stacktrace line if set to 194 * {@code false}. 195 * <p/> 196 * The default is {@code true}. 197 * 198 * @param stackTraceTrimLine of type boolean 199 * @return this 200 */ 201 public TrapProps setStackTraceTrimLine( boolean stackTraceTrimLine ) 202 { 203 this.stackTraceTrimLine = stackTraceTrimLine; 204 205 return this; 206 } 207 208 public String getStackTraceLineDelimiter() 209 { 210 return stackTraceLineDelimiter; 211 } 212 213 /** 214 * Method setStackTraceLineDelimiter will set the text delimiter used to denote stacktrace lines. 215 * <p/> 216 * The default is {@code |} (the pipe character). 217 * 218 * @param stackTraceLineDelimiter of type boolean 219 * @return this 220 */ 221 public TrapProps setStackTraceLineDelimiter( String stackTraceLineDelimiter ) 222 { 223 this.stackTraceLineDelimiter = stackTraceLineDelimiter; 224 225 return this; 226 } 227 228 @Override 229 protected void addPropertiesTo( Properties properties ) 230 { 231 properties.setProperty( RECORD_ELEMENT_TRACE, Boolean.toString( recordElementTrace ) ); 232 properties.setProperty( RECORD_THROWABLE_MESSAGE, Boolean.toString( recordThrowableMessage ) ); 233 properties.setProperty( RECORD_THROWABLE_STACK_TRACE, Boolean.toString( recordThrowableStackTrace ) ); 234 properties.setProperty( LOG_THROWABLE_STACK_TRACE, Boolean.toString( logThrowableStackTrace ) ); 235 properties.setProperty( STACK_TRACE_LINE_TRIM, Boolean.toString( stackTraceTrimLine ) ); 236 237 if( stackTraceLineDelimiter != null ) 238 properties.setProperty( STACK_TRACE_LINE_DELIMITER, stackTraceLineDelimiter ); 239 } 240 }