1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic.corpus;
15
16 import java.util.List;
17 import java.util.Random;
18
19 import ch.qos.logback.classic.Level;
20 import ch.qos.logback.classic.LoggerContext;
21 import ch.qos.logback.classic.spi.ClassPackagingData;
22 import ch.qos.logback.classic.spi.LoggerContextVO;
23 import ch.qos.logback.classic.spi.StackTraceElementProxy;
24 import ch.qos.logback.classic.spi.ThrowableProxy;
25 import ch.qos.logback.classic.spi.ThrowableProxyVO;
26
27
28
29
30
31
32
33
34
35
36
37 public class CorpusModel {
38
39
40
41
42
43
44
45
46
47 static final int AVERAGE_LOGGER_NAME_PARTS = 6;
48 static final int STD_DEV_FOR_LOGGER_NAME_PARTS = 3;
49
50
51
52 static final int LOGGER_POOL_SIZE = 1000;
53
54
55
56 static final int LOG_STATEMENT_POOL_SIZE = LOGGER_POOL_SIZE * 8;
57
58
59
60
61 static final double[] LEVEL_DISTRIBUTION = new double[] { .3, .3, .9, .95 };
62
63
64
65
66 static final int AVERAGE_MESSAGE_WORDS = 8;
67 static final int STD_DEV_FOR_MESSAGE_WORDS = 4;
68
69
70
71 static final double[] ARGUMENT_DISTRIBUTION = new double[] { .80, .88, 0.95 };
72
73 static final double THROWABLE_PROPABILITY_FOR_WARNING = .1;
74 static final double THROWABLE_PROPABILITY_FOR_ERRORS = .3;
75
76 static final double NESTING_PROBABILITY = .5;
77
78
79
80
81
82 static final int AVERAGE_MILLIS_INCREMENT = 10;
83 static final int STD_DEV_FOR_MILLIS_INCREMENT = 5;
84
85
86 static final int THREAD_POOL_SIZE = 10;
87
88 final Random random;
89 final List<String> worldList;
90 String[] threadNamePool;
91 LogStatement[] logStatementPool;
92 String[] loggerNamePool;
93
94
95 long lastTimeStamp = 1236344888578L;
96
97 public CorpusModel(long seed, List<String> worldList) {
98 random = new Random(seed);
99 this.worldList = worldList;
100 buildThreadNamePool();
101 buildLoggerNamePool();
102 buildLogStatementPool();
103 }
104
105 private void buildThreadNamePool() {
106 threadNamePool = new String[THREAD_POOL_SIZE];
107 for (int i = 0; i < THREAD_POOL_SIZE; i++) {
108 threadNamePool[i] = "CorpusMakerThread-" + i;
109 }
110 }
111
112 private void buildLoggerNamePool() {
113 loggerNamePool = new String[LOGGER_POOL_SIZE];
114 for (int i = 0; i < LOGGER_POOL_SIZE; i++) {
115 loggerNamePool[i] = makeRandomLoggerName();
116 }
117 }
118
119 private void buildLogStatementPool() {
120 logStatementPool = new LogStatement[LOG_STATEMENT_POOL_SIZE];
121 for (int i = 0; i < LOG_STATEMENT_POOL_SIZE; i++) {
122 logStatementPool[i] = makeRandomLogStatement(loggerNamePool);
123 }
124 }
125
126 private int[] getRandomAnchorPositions(int wordCount, int numAnchors) {
127
128
129 int[] positionsIndex = new int[numAnchors];
130 for (int i = 0; i < numAnchors; i++) {
131 positionsIndex[i] = random.nextInt(wordCount);
132 }
133 return positionsIndex;
134 }
135
136 private String[] getRandomWords(int n) {
137 String[] wordArray = new String[n];
138 for (int i = 0; i < n; i++) {
139 wordArray[i] = getRandomWord();
140 }
141 return wordArray;
142 }
143
144 public long getRandomLong() {
145 return random.nextLong();
146 }
147
148 public String getRandomThreadNameFromPool() {
149 int index = random.nextInt(THREAD_POOL_SIZE);
150 return threadNamePool[index];
151 }
152
153 public LogStatement getRandomLogStatementFromPool() {
154 int index = random.nextInt(logStatementPool.length);
155 return logStatementPool[index];
156 }
157
158 private String getRandomLoggerNameFromPool(String[] loggerNamePool) {
159 int index = random.nextInt(loggerNamePool.length);
160 return loggerNamePool[index];
161 }
162
163 public long getRandomTimeStamp() {
164
165 lastTimeStamp += RandomUtil.gaussianAsPositiveInt(random, AVERAGE_MILLIS_INCREMENT,
166 STD_DEV_FOR_MILLIS_INCREMENT) - 1;
167 return lastTimeStamp;
168 }
169
170 LoggerContextVO getRandomlyNamedLoggerContextVO() {
171 LoggerContext lc = new LoggerContext();
172 lc.setName(getRandomJavaIdentifier());
173 return new LoggerContextVO(lc);
174 }
175
176 String getRandomWord() {
177 int size = worldList.size();
178 int randomIndex = random.nextInt(size);
179 return worldList.get(randomIndex);
180 }
181
182 String extractLastPart(String loggerName) {
183 int i = loggerName.lastIndexOf('.');
184 if (i == -1) {
185 return loggerName;
186 } else {
187 return loggerName.substring(i + 1);
188 }
189 }
190
191 public StackTraceElement[] getRandomCallerData(int depth, String loggerName) {
192 StackTraceElement[] cda = new StackTraceElement[depth];
193 StackTraceElement cd = new StackTraceElement(loggerName, getRandomJavaIdentifier(), extractLastPart(loggerName),
194 0);
195 cda[0] = cd;
196 for (int i = 1; i < depth; i++) {
197 String ln = getRandomLoggerNameFromPool(loggerNamePool);
198 cda[i] = new StackTraceElement(ln, getRandomJavaIdentifier(), extractLastPart(ln), i * 10);
199 }
200 return cda;
201 }
202
203 public Object[] getRandomArgumentArray(int numOfArguments) {
204 if (numOfArguments == 0) {
205 return null;
206 }
207 Object[] argumentArray = new Object[numOfArguments];
208 for (int i = 0; i < numOfArguments; i++) {
209 argumentArray[i] = Long.valueOf(random.nextLong());
210 }
211 return argumentArray;
212 }
213
214 private MessageArgumentTuple makeRandomMessageArgumentTuple() {
215 int numOfArguments = getNumberOfMessageArguments();
216
217 int wordCount = RandomUtil.gaussianAsPositiveInt(random, AVERAGE_MESSAGE_WORDS, STD_DEV_FOR_MESSAGE_WORDS);
218 String[] wordArray = getRandomWords(wordCount);
219
220 int[] anchorPositions = getRandomAnchorPositions(wordCount, numOfArguments);
221
222 for (int anchorIndex : anchorPositions) {
223 wordArray[anchorIndex] = "{}";
224 }
225
226 StringBuilder sb = new StringBuilder();
227 for (int i = 1; i < wordCount; i++) {
228 sb.append(wordArray[i]).append(' ');
229 }
230 sb.append(getRandomWord());
231 return new MessageArgumentTuple(sb.toString(), numOfArguments);
232 }
233
234 private LogStatement makeRandomLogStatement(String[] loggerNamePool) {
235 MessageArgumentTuple mat = makeRandomMessageArgumentTuple();
236 String loggerName = getRandomLoggerNameFromPool(loggerNamePool);
237 Level randomLevel = getRandomLevel();
238 Throwable t = getRandomThrowable(randomLevel);
239 ThrowableProxyVO throwableProxy = null;
240 if (t != null) {
241 throwableProxy = ThrowableProxyVO.build(new ThrowableProxy(t));
242 pupulateWithPackagingData(throwableProxy.getStackTraceElementProxyArray());
243 }
244 return new LogStatement(loggerName, randomLevel, mat, throwableProxy);
245 }
246
247 private Throwable getRandomThrowable(Level level) {
248 double rn = random.nextDouble();
249 if ((level == Level.WARN && rn < THROWABLE_PROPABILITY_FOR_WARNING)
250 || (level == Level.ERROR && rn < THROWABLE_PROPABILITY_FOR_ERRORS)) {
251 return ExceptionBuilder.build(random, NESTING_PROBABILITY);
252 } else {
253 return null;
254 }
255 }
256
257 private void pupulateWithPackagingData(StackTraceElementProxy[] stepArray) {
258 int i = 0;
259 for (StackTraceElementProxy step : stepArray) {
260 String identifier = "na";
261 String version = "na";
262 if (i++ % 2 == 0) {
263 identifier = getRandomJavaIdentifier();
264 version = getRandomJavaIdentifier();
265 }
266 ClassPackagingData cpd = new ClassPackagingData(identifier, version);
267 step.setClassPackagingData(cpd);
268 }
269 }
270
271 private int getNumberOfMessageArguments() {
272 double rn = random.nextDouble();
273 if (rn < ARGUMENT_DISTRIBUTION[0]) {
274 return 0;
275 }
276 if (rn < ARGUMENT_DISTRIBUTION[1]) {
277 return 1;
278 }
279 if (rn < ARGUMENT_DISTRIBUTION[2]) {
280 return 2;
281 }
282 return 3;
283 }
284
285 String getRandomJavaIdentifier() {
286 String w = getRandomWord();
287 w = w.replaceAll("\\p{Punct}", "");
288 return w;
289 }
290
291 private String makeRandomLoggerName() {
292 int parts = RandomUtil.gaussianAsPositiveInt(random, AVERAGE_LOGGER_NAME_PARTS, STD_DEV_FOR_LOGGER_NAME_PARTS);
293 StringBuilder sb = new StringBuilder();
294 for (int i = 1; i < parts; i++) {
295 sb.append(getRandomJavaIdentifier()).append('.');
296 }
297 sb.append(getRandomJavaIdentifier());
298 return sb.toString();
299 }
300
301 private Level getRandomLevel() {
302 double rn = random.nextDouble();
303 if (rn < LEVEL_DISTRIBUTION[0]) {
304 return Level.TRACE;
305 }
306 if (rn < LEVEL_DISTRIBUTION[1]) {
307 return Level.DEBUG;
308 }
309
310 if (rn < LEVEL_DISTRIBUTION[2]) {
311 return Level.INFO;
312 }
313
314 if (rn < LEVEL_DISTRIBUTION[3]) {
315 return Level.WARN;
316 }
317
318 return Level.ERROR;
319 }
320 }