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 public Builder setConfiguration(final Configuration configuration) { 152 this.configuration = configuration; 153 return this; 154 } 155 156 /** 157 * The name of the database column as it exists within the database table. 158 */ 159 public Builder setName(final String name) { 160 this.name = name; 161 return this; 162 } 163 164 /** 165 * The {@link PatternLayout} pattern to insert in this column. Mutually exclusive with 166 * {@code literal!=null} and {@code eventTimestamp=true} 167 */ 168 public Builder setPattern(final String pattern) { 169 this.pattern = pattern; 170 return this; 171 } 172 173 /** 174 * The literal value to insert into the column as-is without any quoting or escaping. Mutually exclusive with 175 * {@code pattern!=null} and {@code eventTimestamp=true}. 176 */ 177 public Builder setLiteral(final String literal) { 178 this.literal = literal; 179 return this; 180 } 181 182 /** 183 * If {@code "true"}, indicates that this column is a date-time column in which the event timestamp should be 184 * inserted. Mutually exclusive with {@code pattern!=null} and {@code literal!=null}. 185 */ 186 public Builder setEventTimestamp(final boolean eventTimestamp) { 187 isEventTimestamp = eventTimestamp; 188 return this; 189 } 190 191 /** 192 * If {@code "true"}, indicates that the column is a Unicode String. 193 */ 194 public Builder setUnicode(final boolean unicode) { 195 isUnicode = unicode; 196 return this; 197 } 198 199 /** 200 * If {@code "true"}, indicates that the column is a character LOB (CLOB). 201 */ 202 public Builder setClob(final boolean clob) { 203 isClob = clob; 204 return this; 205 } 206 207 @Override 208 public ColumnConfig build() { 209 if (Strings.isEmpty(name)) { 210 LOGGER.error("The column config is not valid because it does not contain a column name."); 211 return null; 212 } 213 214 final boolean isPattern = Strings.isNotEmpty(pattern); 215 final boolean isLiteralValue = Strings.isNotEmpty(literal); 216 217 if ((isPattern && isLiteralValue) || (isPattern && isEventTimestamp) || (isLiteralValue && isEventTimestamp)) { 218 LOGGER.error("The pattern, literal, and isEventTimestamp attributes are mutually exclusive."); 219 return null; 220 } 221 222 if (isEventTimestamp) { 223 return new ColumnConfig(name, null, null, true, false, false); 224 } 225 226 if (isLiteralValue) { 227 return new ColumnConfig(name, null, literal, false, false, false); 228 } 229 230 if (isPattern) { 231 final PatternLayout layout = 232 PatternLayout.newBuilder() 233 .withPattern(pattern) 234 .withConfiguration(configuration) 235 .withAlwaysWriteExceptions(false) 236 .build(); 237 return new ColumnConfig(name, layout, null, false, isUnicode, isClob); 238 } 239 240 LOGGER.error("To configure a column you must specify a pattern or literal or set isEventDate to true."); 241 return null; 242 } 243 } 244}