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