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 private static final Logger LOGGER = StatusLogger.getLogger(); 041 042 private final String columnName; 043 private final PatternLayout layout; 044 private final String literalValue; 045 private final boolean eventTimestamp; 046 private final boolean unicode; 047 private final boolean clob; 048 049 private ColumnConfig(final String columnName, final PatternLayout layout, final String literalValue, 050 final boolean eventDate, final boolean unicode, final boolean clob) { 051 this.columnName = columnName; 052 this.layout = layout; 053 this.literalValue = literalValue; 054 this.eventTimestamp = eventDate; 055 this.unicode = unicode; 056 this.clob = clob; 057 } 058 059 public String getColumnName() { 060 return this.columnName; 061 } 062 063 public PatternLayout getLayout() { 064 return this.layout; 065 } 066 067 public String getLiteralValue() { 068 return this.literalValue; 069 } 070 071 public boolean isEventTimestamp() { 072 return this.eventTimestamp; 073 } 074 075 public boolean isUnicode() { 076 return this.unicode; 077 } 078 079 public boolean isClob() { 080 return this.clob; 081 } 082 083 @Override 084 public String toString() { 085 return "{ name=" + this.columnName + ", layout=" + this.layout + ", literal=" + this.literalValue 086 + ", timestamp=" + this.eventTimestamp + " }"; 087 } 088 089 /** 090 * Factory method for creating a column config within the plugin manager. 091 * 092 * @see Builder 093 * @deprecated use {@link #newBuilder()} 094 */ 095 @Deprecated 096 public static ColumnConfig createColumnConfig(final Configuration config, final String name, final String pattern, 097 final String literalValue, final String eventTimestamp, 098 final String unicode, final String clob) { 099 if (Strings.isEmpty(name)) { 100 LOGGER.error("The column config is not valid because it does not contain a column name."); 101 return null; 102 } 103 104 final boolean isEventTimestamp = Boolean.parseBoolean(eventTimestamp); 105 final boolean isUnicode = Booleans.parseBoolean(unicode, true); 106 final boolean isClob = Boolean.parseBoolean(clob); 107 108 return newBuilder() 109 .setConfiguration(config) 110 .setName(name) 111 .setPattern(pattern) 112 .setLiteral(literalValue) 113 .setEventTimestamp(isEventTimestamp) 114 .setUnicode(isUnicode) 115 .setClob(isClob) 116 .build(); 117 } 118 119 @PluginBuilderFactory 120 public static Builder newBuilder() { 121 return new Builder(); 122 } 123 124 public static class Builder implements org.apache.logging.log4j.core.util.Builder<ColumnConfig> { 125 126 @PluginConfiguration 127 private Configuration configuration; 128 129 @PluginBuilderAttribute 130 @Required(message = "No name provided") 131 private String name; 132 133 @PluginBuilderAttribute 134 private String pattern; 135 136 @PluginBuilderAttribute 137 private String literal; 138 139 @PluginBuilderAttribute 140 private boolean isEventTimestamp; 141 142 @PluginBuilderAttribute 143 private boolean isUnicode = true; 144 145 @PluginBuilderAttribute 146 private boolean isClob; 147 148 /** 149 * The configuration object. 150 * 151 * @return this. 152 */ 153 public Builder setConfiguration(final Configuration configuration) { 154 this.configuration = configuration; 155 return this; 156 } 157 158 /** 159 * The name of the database column as it exists within the database table. 160 * 161 * @return this. 162 */ 163 public Builder setName(final String name) { 164 this.name = name; 165 return this; 166 } 167 168 /** 169 * The {@link PatternLayout} pattern to insert in this column. Mutually exclusive with 170 * {@code literal!=null} and {@code eventTimestamp=true} 171 * 172 * @return this. 173 */ 174 public Builder setPattern(final String pattern) { 175 this.pattern = pattern; 176 return this; 177 } 178 179 /** 180 * The literal value to insert into the column as-is without any quoting or escaping. Mutually exclusive with 181 * {@code pattern!=null} and {@code eventTimestamp=true}. 182 * 183 * @return this. 184 */ 185 public Builder setLiteral(final String literal) { 186 this.literal = literal; 187 return this; 188 } 189 190 /** 191 * If {@code "true"}, indicates that this column is a date-time column in which the event timestamp should be 192 * inserted. Mutually exclusive with {@code pattern!=null} and {@code literal!=null}. 193 * 194 * @return this. 195 */ 196 public Builder setEventTimestamp(final boolean eventTimestamp) { 197 isEventTimestamp = eventTimestamp; 198 return this; 199 } 200 201 /** 202 * If {@code "true"}, indicates that the column is a Unicode String. 203 * 204 * @return this. 205 */ 206 public Builder setUnicode(final boolean unicode) { 207 isUnicode = unicode; 208 return this; 209 } 210 211 /** 212 * If {@code "true"}, indicates that the column is a character LOB (CLOB). 213 * 214 * @return this. 215 */ 216 public Builder setClob(final boolean clob) { 217 isClob = clob; 218 return this; 219 } 220 221 @Override 222 public ColumnConfig build() { 223 if (Strings.isEmpty(name)) { 224 LOGGER.error("The column config is not valid because it does not contain a column name."); 225 return null; 226 } 227 228 final boolean isPattern = Strings.isNotEmpty(pattern); 229 final boolean isLiteralValue = Strings.isNotEmpty(literal); 230 231 if ((isPattern && isLiteralValue) || (isPattern && isEventTimestamp) || (isLiteralValue && isEventTimestamp)) { 232 LOGGER.error("The pattern, literal, and isEventTimestamp attributes are mutually exclusive."); 233 return null; 234 } 235 236 if (isEventTimestamp) { 237 return new ColumnConfig(name, null, null, true, false, false); 238 } 239 240 if (isLiteralValue) { 241 return new ColumnConfig(name, null, literal, false, false, false); 242 } 243 244 if (isPattern) { 245 final PatternLayout layout = 246 PatternLayout.newBuilder() 247 .withPattern(pattern) 248 .withConfiguration(configuration) 249 .withAlwaysWriteExceptions(false) 250 .build(); 251 return new ColumnConfig(name, layout, null, false, isUnicode, isClob); 252 } 253 254 LOGGER.error("To configure a column you must specify a pattern or literal or set isEventDate to true."); 255 return null; 256 } 257 } 258}