001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.appender.db.jdbc; 018 019import org.apache.logging.log4j.Logger; 020import org.apache.logging.log4j.core.Core; 021import org.apache.logging.log4j.core.appender.db.ColumnMapping; 022import org.apache.logging.log4j.core.config.Configuration; 023import org.apache.logging.log4j.core.config.plugins.Plugin; 024import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; 025import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 026import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; 027import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; 028import org.apache.logging.log4j.core.layout.PatternLayout; 029import org.apache.logging.log4j.core.util.Booleans; 030import org.apache.logging.log4j.status.StatusLogger; 031import org.apache.logging.log4j.util.Strings; 032 033/** 034 * A configuration element used to configure which event properties are logged to which columns in the database table. 035 * 036 * @see ColumnMapping 037 */ 038@Plugin(name = "Column", category = Core.CATEGORY_NAME, printObject = true) 039public final class ColumnConfig { 040 public static class Builder implements org.apache.logging.log4j.core.util.Builder<ColumnConfig> { 041 042 @PluginConfiguration 043 private Configuration configuration; 044 045 @PluginBuilderAttribute 046 @Required(message = "No name provided") 047 private String name; 048 049 @PluginBuilderAttribute 050 private String pattern; 051 052 @PluginBuilderAttribute 053 private String literal; 054 055 @PluginBuilderAttribute 056 private boolean isEventTimestamp; 057 058 @PluginBuilderAttribute 059 private boolean isUnicode = true; 060 061 @PluginBuilderAttribute 062 private boolean isClob; 063 064 @Override 065 public ColumnConfig build() { 066 if (Strings.isEmpty(name)) { 067 LOGGER.error("The column config is not valid because it does not contain a column name."); 068 return null; 069 } 070 071 final boolean isPattern = Strings.isNotEmpty(pattern); 072 final boolean isLiteralValue = Strings.isNotEmpty(literal); 073 074 if ((isPattern && isLiteralValue) || (isPattern && isEventTimestamp) || (isLiteralValue && isEventTimestamp)) { 075 LOGGER.error("The pattern, literal, and isEventTimestamp attributes are mutually exclusive."); 076 return null; 077 } 078 079 if (isEventTimestamp) { 080 return new ColumnConfig(name, null, null, true, false, false); 081 } 082 083 if (isLiteralValue) { 084 return new ColumnConfig(name, null, literal, false, false, false); 085 } 086 087 if (isPattern) { 088 final PatternLayout layout = 089 PatternLayout.newBuilder() 090 .withPattern(pattern) 091 .withConfiguration(configuration) 092 .withAlwaysWriteExceptions(false) 093 .build(); 094 return new ColumnConfig(name, layout, null, false, isUnicode, isClob); 095 } 096 097 LOGGER.error("To configure a column you must specify a pattern or literal or set isEventDate to true."); 098 return null; 099 } 100 101 /** 102 * If {@code "true"}, indicates that the column is a character LOB (CLOB). 103 * 104 * @return this. 105 */ 106 public Builder setClob(final boolean clob) { 107 isClob = clob; 108 return this; 109 } 110 111 /** 112 * The configuration object. 113 * 114 * @return this. 115 */ 116 public Builder setConfiguration(final Configuration configuration) { 117 this.configuration = configuration; 118 return this; 119 } 120 121 /** 122 * If {@code "true"}, indicates that this column is a date-time column in which the event timestamp should be 123 * inserted. Mutually exclusive with {@code pattern!=null} and {@code literal!=null}. 124 * 125 * @return this. 126 */ 127 public Builder setEventTimestamp(final boolean eventTimestamp) { 128 isEventTimestamp = eventTimestamp; 129 return this; 130 } 131 132 /** 133 * The literal value to insert into the column as-is without any quoting or escaping. Mutually exclusive with 134 * {@code pattern!=null} and {@code eventTimestamp=true}. 135 * 136 * @return this. 137 */ 138 public Builder setLiteral(final String literal) { 139 this.literal = literal; 140 return this; 141 } 142 143 /** 144 * The name of the database column as it exists within the database table. 145 * 146 * @return this. 147 */ 148 public Builder setName(final String name) { 149 this.name = name; 150 return this; 151 } 152 153 /** 154 * The {@link PatternLayout} pattern to insert in this column. Mutually exclusive with 155 * {@code literal!=null} and {@code eventTimestamp=true} 156 * 157 * @return this. 158 */ 159 public Builder setPattern(final String pattern) { 160 this.pattern = pattern; 161 return this; 162 } 163 164 /** 165 * If {@code "true"}, indicates that the column is a Unicode String. 166 * 167 * @return this. 168 */ 169 public Builder setUnicode(final boolean unicode) { 170 isUnicode = unicode; 171 return this; 172 } 173 } 174 175 private static final Logger LOGGER = StatusLogger.getLogger(); 176 /** 177 * Factory method for creating a column config within the plugin manager. 178 * 179 * @see Builder 180 * @deprecated use {@link #newBuilder()} 181 */ 182 @Deprecated 183 public static ColumnConfig createColumnConfig(final Configuration config, final String name, final String pattern, 184 final String literalValue, final String eventTimestamp, 185 final String unicode, final String clob) { 186 if (Strings.isEmpty(name)) { 187 LOGGER.error("The column config is not valid because it does not contain a column name."); 188 return null; 189 } 190 191 final boolean isEventTimestamp = Boolean.parseBoolean(eventTimestamp); 192 final boolean isUnicode = Booleans.parseBoolean(unicode, true); 193 final boolean isClob = Boolean.parseBoolean(clob); 194 195 return newBuilder() 196 .setConfiguration(config) 197 .setName(name) 198 .setPattern(pattern) 199 .setLiteral(literalValue) 200 .setEventTimestamp(isEventTimestamp) 201 .setUnicode(isUnicode) 202 .setClob(isClob) 203 .build(); 204 } 205 @PluginBuilderFactory 206 public static Builder newBuilder() { 207 return new Builder(); 208 } 209 private final String columnName; 210 private final String columnNameKey; 211 private final PatternLayout layout; 212 private final String literalValue; 213 214 private final boolean eventTimestamp; 215 216 private final boolean unicode; 217 218 private final boolean clob; 219 220 private ColumnConfig(final String columnName, final PatternLayout layout, final String literalValue, 221 final boolean eventDate, final boolean unicode, final boolean clob) { 222 this.columnName = columnName; 223 this.columnNameKey = ColumnMapping.toKey(columnName); 224 this.layout = layout; 225 this.literalValue = literalValue; 226 this.eventTimestamp = eventDate; 227 this.unicode = unicode; 228 this.clob = clob; 229 } 230 231 public String getColumnName() { 232 return this.columnName; 233 } 234 235 public String getColumnNameKey() { 236 return this.columnNameKey; 237 } 238 239 public PatternLayout getLayout() { 240 return this.layout; 241 } 242 243 public String getLiteralValue() { 244 return this.literalValue; 245 } 246 247 public boolean isClob() { 248 return this.clob; 249 } 250 251 public boolean isEventTimestamp() { 252 return this.eventTimestamp; 253 } 254 255 public boolean isUnicode() { 256 return this.unicode; 257 } 258 259 @Override 260 public String toString() { 261 return "{ name=" + this.columnName + ", layout=" + this.layout + ", literal=" + this.literalValue 262 + ", timestamp=" + this.eventTimestamp + " }"; 263 } 264}