1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.helper;
17
18 import static org.codelibs.core.stream.StreamUtil.stream;
19
20 import java.time.LocalDateTime;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Locale;
27 import java.util.Map;
28 import java.util.Queue;
29 import java.util.concurrent.ConcurrentLinkedQueue;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.TimeUnit;
32 import java.util.stream.Collectors;
33
34 import org.apache.commons.lang3.StringUtils;
35 import org.apache.logging.log4j.LogManager;
36 import org.apache.logging.log4j.Logger;
37 import org.codelibs.core.concurrent.CommonPoolUtil;
38 import org.codelibs.core.lang.StringUtil;
39 import org.codelibs.fess.Constants;
40 import org.codelibs.fess.entity.SearchLogEvent;
41 import org.codelibs.fess.entity.SearchRequestParams;
42 import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType;
43 import org.codelibs.fess.mylasta.action.FessUserBean;
44 import org.codelibs.fess.mylasta.direction.FessConfig;
45 import org.codelibs.fess.opensearch.log.exbhv.ClickLogBhv;
46 import org.codelibs.fess.opensearch.log.exbhv.FavoriteLogBhv;
47 import org.codelibs.fess.opensearch.log.exbhv.SearchLogBhv;
48 import org.codelibs.fess.opensearch.log.exbhv.UserInfoBhv;
49 import org.codelibs.fess.opensearch.log.exentity.ClickLog;
50 import org.codelibs.fess.opensearch.log.exentity.SearchLog;
51 import org.codelibs.fess.opensearch.log.exentity.UserInfo;
52 import org.codelibs.fess.util.ComponentUtil;
53 import org.codelibs.fess.util.DocumentUtil;
54 import org.codelibs.fess.util.QueryResponseList;
55 import org.dbflute.optional.OptionalEntity;
56 import org.dbflute.optional.OptionalThing;
57 import org.lastaflute.web.util.LaRequestUtil;
58 import org.opensearch.action.update.UpdateRequest;
59 import org.opensearch.script.Script;
60
61 import com.fasterxml.jackson.core.JsonProcessingException;
62 import com.fasterxml.jackson.databind.ObjectMapper;
63 import com.google.common.base.CaseFormat;
64 import com.google.common.cache.CacheBuilder;
65 import com.google.common.cache.CacheLoader;
66 import com.google.common.cache.LoadingCache;
67
68 import jakarta.annotation.PostConstruct;
69 import jakarta.servlet.http.HttpServletRequest;
70
71
72
73
74 public class SearchLogHelper {
75 private static final Logger logger = LogManager.getLogger(SearchLogHelper.class);
76
77
78
79
80 public SearchLogHelper() {
81
82 }
83
84
85 protected long userCheckInterval = 10 * 60 * 1000L;
86
87
88 protected int userInfoCacheSize = 10000;
89
90
91 protected Queue<SearchLog> searchLogQueue = new ConcurrentLinkedQueue<>();
92
93
94 protected Queue<ClickLog> clickLogQueue = new ConcurrentLinkedQueue<>();
95
96
97 protected LoadingCache<String, UserInfo> userInfoCache;
98
99
100 protected String loggerName = "fess.log.searchlog";
101
102
103 protected Logger searchLogLogger = null;
104
105
106 protected ObjectMapper objectMapper = new ObjectMapper();
107
108
109
110
111 @PostConstruct
112 public void init() {
113 if (logger.isDebugEnabled()) {
114 logger.debug("Initializing {}", this.getClass().getSimpleName());
115 }
116 userInfoCache = CacheBuilder.newBuilder()
117 .maximumSize(userInfoCacheSize)
118 .expireAfterWrite(userCheckInterval, TimeUnit.MILLISECONDS)
119 .build(new CacheLoader<String, UserInfo>() {
120 @Override
121 public UserInfo load(final String key) throws Exception {
122 return storeUserInfo(key);
123 }
124 });
125 searchLogLogger = LogManager.getLogger(loggerName);
126 }
127
128
129 protected static class SearchLogContext {
130 final FessConfig fessConfig;
131 final String[] roles;
132 final String userCode;
133 final String userId;
134 final HttpServletRequest request;
135 final String clientIp;
136 final String virtualHostKey;
137
138 SearchLogContext(final FessConfig fessConfig, final String[] roles, final String userCode, final String userId,
139 final HttpServletRequest request, final String clientIp, final String virtualHostKey) {
140 this.fessConfig = fessConfig;
141 this.roles = roles;
142 this.userCode = userCode;
143 this.userId = userId;
144 this.request = request;
145 this.clientIp = clientIp;
146 this.virtualHostKey = virtualHostKey;
147 }
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161 public void addSearchLog(final SearchRequestParams params, final LocalDateTime requestedTime, final String queryId, final String query,
162 final int pageStart, final int pageSize, final QueryResponseList queryResponseList) {
163 final FessConfig fessConfig = ComponentUtil.getFessConfig();
164 if (searchLogQueue.size() > fessConfig.getLoggingSearchMaxQueueSizeAsInteger()) {
165 logger.warn("[{}] The search log queue size is too large. Skipped the search log: {}", queryId, query);
166 return;
167 }
168
169 final SearchLogContext context = createSearchLogContext(params, fessConfig);
170 createSearchLog(params, requestedTime, queryId, query, pageStart, pageSize, queryResponseList, context);
171 }
172
173
174
175
176
177
178
179
180 protected SearchLogContext createSearchLogContext(final SearchRequestParams params, final FessConfig fessConfig) {
181 final String[] roles = ComponentUtil.getRoleQueryHelper().build(params.getType()).stream().toArray(n -> new String[n]);
182 final String userCode = fessConfig.isUserInfo() ? ComponentUtil.getUserInfoHelper().getUserCode() : null;
183 final String userId = ComponentUtil.getRequestManager().findUserBean(FessUserBean.class).map(FessUserBean::getUserId).orElse(null);
184 final HttpServletRequest request = LaRequestUtil.getOptionalRequest().orElse(null);
185 final String clientIp = request != null ? ComponentUtil.getViewHelper().getClientIp(request) : null;
186 final String virtualHostKey = ComponentUtil.getVirtualHostHelper().getVirtualHostKey();
187
188 return new SearchLogContext(fessConfig, roles, userCode, userId, request, clientIp, virtualHostKey);
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203 protected void createSearchLog(final SearchRequestParams params, final LocalDateTime requestedTime, final String queryId,
204 final String query, final int pageStart, final int pageSize, final QueryResponseList queryResponseList,
205 final SearchLogContext context) {
206 final SearchLog searchLog = new SearchLog();
207
208 if (context.userCode != null) {
209 searchLog.setUserSessionId(context.userCode);
210 searchLog.setUserInfo(getUserInfo(context.userCode));
211 }
212
213 searchLog.setRoles(context.roles);
214 searchLog.setQueryId(queryId);
215 searchLog.setHitCount(queryResponseList.getAllRecordCount());
216 searchLog.setHitCountRelation(queryResponseList.getAllRecordCountRelation());
217 searchLog.setResponseTime(queryResponseList.getExecTime());
218 searchLog.setQueryTime(queryResponseList.getQueryTime());
219 searchLog.setSearchWord(StringUtils.abbreviate(query, 1000));
220 searchLog.setRequestedAt(requestedTime);
221 searchLog.setSearchQuery(StringUtils.abbreviate(queryResponseList.getSearchQuery(), 1000));
222 searchLog.setQueryOffset(pageStart);
223 searchLog.setQueryPageSize(pageSize);
224
225 if (context.userId != null) {
226 searchLog.setUser(context.userId);
227 }
228
229 if (context.request != null) {
230 searchLog.setClientIp(StringUtils.abbreviate(context.clientIp, 100));
231 searchLog.setReferer(StringUtils.abbreviate(context.request.getHeader("referer"), 1000));
232 searchLog.setUserAgent(StringUtils.abbreviate(context.request.getHeader("user-agent"), 255));
233
234 searchLog.setAccessType(determineAccessType(context.request.getAttribute(Constants.SEARCH_LOG_ACCESS_TYPE)));
235
236 final Object languages = context.request.getAttribute(Constants.REQUEST_LANGUAGES);
237 if (languages != null) {
238 searchLog.setLanguages(StringUtils.join((String[]) languages, ","));
239 } else {
240 searchLog.setLanguages(StringUtil.EMPTY);
241 }
242
243 @SuppressWarnings("unchecked")
244 final Map<String, List<String>> fieldLogMap = (Map<String, List<String>>) context.request.getAttribute(Constants.FIELD_LOGS);
245 if (fieldLogMap != null) {
246 final int queryMaxLength = context.fessConfig.getQueryMaxLengthAsInteger();
247 for (final Map.Entry<String, List<String>> logEntry : fieldLogMap.entrySet()) {
248 for (final String value : logEntry.getValue()) {
249 searchLog.addSearchFieldLogValue(logEntry.getKey(), StringUtils.abbreviate(value, queryMaxLength));
250 }
251 }
252 }
253
254 for (final String s : context.fessConfig.getSearchlogRequestHeadersAsArray()) {
255 final String key = s.replace('-', '_').toLowerCase(Locale.ENGLISH);
256 Collections.list(context.request.getHeaders(s)).stream().forEach(v -> {
257 searchLog.addRequestHeaderValue(key, v);
258 });
259 }
260 }
261
262 if (StringUtil.isNotBlank(context.virtualHostKey)) {
263 searchLog.setVirtualHost(context.virtualHostKey);
264 } else {
265 searchLog.setVirtualHost(StringUtil.EMPTY);
266 }
267
268 addDocumentsInResponse(queryResponseList, searchLog);
269 searchLogQueue.add(searchLog);
270 }
271
272
273
274
275
276
277
278 protected String determineAccessType(final Object accessType) {
279 if (Constants.SEARCH_LOG_ACCESS_TYPE_JSON.equals(accessType)) {
280 return Constants.SEARCH_LOG_ACCESS_TYPE_JSON;
281 } else if (Constants.SEARCH_LOG_ACCESS_TYPE_GSA.equals(accessType)) {
282 return Constants.SEARCH_LOG_ACCESS_TYPE_GSA;
283 } else if (Constants.SEARCH_LOG_ACCESS_TYPE_OTHER.equals(accessType)) {
284 return Constants.SEARCH_LOG_ACCESS_TYPE_OTHER;
285 } else if (Constants.SEARCH_LOG_ACCESS_TYPE_ADMIN.equals(accessType)) {
286 return Constants.SEARCH_LOG_ACCESS_TYPE_ADMIN;
287 } else if (accessType instanceof String && StringUtil.isNotBlank((String) accessType)) {
288 return (String) accessType;
289 }
290 return Constants.SEARCH_LOG_ACCESS_TYPE_WEB;
291 }
292
293
294
295
296
297
298
299 protected void addDocumentsInResponse(final QueryResponseList queryResponseList, final SearchLog searchLog) {
300 if (ComponentUtil.getFessConfig().isLoggingSearchDocsEnabled()) {
301 queryResponseList.stream().forEach(res -> {
302 final Map<String, Object> map = new HashMap<>();
303 Arrays.stream(ComponentUtil.getFessConfig().getLoggingSearchDocsFieldsAsArray()).forEach(s -> map.put(s, res.get(s)));
304 searchLog.addDocument(map);
305 });
306 }
307 }
308
309
310
311
312
313
314 public void addClickLog(final ClickLog clickLog) {
315 final FessConfig fessConfig = ComponentUtil.getFessConfig();
316 if (clickLogQueue.size() > fessConfig.getLoggingClickMaxQueueSizeAsInteger()) {
317 logger.warn("Click log queue size exceeded: queueSize={}, limit={}. Skipped.", clickLogQueue.size(),
318 fessConfig.getLoggingClickMaxQueueSizeAsInteger());
319 return;
320 }
321 clickLogQueue.add(clickLog);
322 }
323
324
325
326
327 public void storeSearchLog() {
328 storeSearchLogFromQueue();
329 storeClickLogFromQueue();
330 }
331
332
333
334
335 protected void storeClickLogFromQueue() {
336 if (!clickLogQueue.isEmpty()) {
337 processClickLogQueue(clickLogQueue);
338 }
339 }
340
341
342
343
344 protected void storeSearchLogFromQueue() {
345 if (!searchLogQueue.isEmpty()) {
346 processSearchLogQueue(searchLogQueue);
347 }
348 }
349
350
351
352
353
354
355
356 public int getClickCount(final String url) {
357 final ClickLogBhv clickLogBhv = ComponentUtil.getComponent(ClickLogBhv.class);
358 return clickLogBhv.selectCount(cb -> {
359 cb.query().setUrl_Equal(url);
360 });
361 }
362
363
364
365
366
367
368
369 public long getFavoriteCount(final String url) {
370 final FavoriteLogBhv favoriteLogBhv = ComponentUtil.getComponent(FavoriteLogBhv.class);
371 return favoriteLogBhv.selectCount(cb -> {
372 cb.query().setUrl_Equal(url);
373 });
374 }
375
376
377
378
379
380
381
382 protected UserInfo storeUserInfo(final String userCode) {
383 final UserInfoBhv userInfoBhv = ComponentUtil.getComponent(UserInfoBhv.class);
384
385 final LocalDateTime now = ComponentUtil.getSystemHelper().getCurrentTimeAsLocalDateTime();
386 final UserInfo userInfo = userInfoBhv.selectByPK(userCode).map(e -> {
387 e.setUpdatedAt(now);
388 return e;
389 }).orElseGet(() -> {
390 final UserInfo e = new UserInfo();
391 e.setId(userCode);
392 e.setCreatedAt(now);
393 e.setUpdatedAt(now);
394 return e;
395 });
396 CommonPoolUtil.execute(() -> userInfoBhv.insertOrUpdate(userInfo));
397 return userInfo;
398 }
399
400
401
402
403
404
405
406 public OptionalEntity<UserInfo> getUserInfo(final String userCode) {
407 if (StringUtil.isNotBlank(userCode)) {
408 try {
409 return OptionalEntity.of(userInfoCache.get(userCode));
410 } catch (final ExecutionException e) {
411 if (logger.isDebugEnabled()) {
412 logger.debug("Failed to access UserInfo cache.", e);
413 }
414 }
415 }
416 return OptionalEntity.empty();
417 }
418
419
420
421
422
423
424 protected void processSearchLogQueue(final Queue<SearchLog> queue) {
425 final FessConfig fessConfig = ComponentUtil.getFessConfig();
426 final String value = fessConfig.getPurgeByBots();
427 String[] botNames;
428 if (StringUtil.isBlank(value)) {
429 botNames = StringUtil.EMPTY_STRINGS;
430 } else {
431 botNames = value.split(",");
432 }
433
434 final int batchSize = fessConfig.getSearchlogProcessBatchSizeAsInteger();
435
436 final List<SearchLog> searchLogList = new ArrayList<>();
437 final Map<String, UserInfo> userInfoMap = new HashMap<>();
438 while (!queue.isEmpty()) {
439 final SearchLog searchLog = queue.poll();
440 if (searchLog != null) {
441 final String userAgent = searchLog.getUserAgent();
442 final boolean isBot =
443 userAgent != null && stream(botNames).get(stream -> stream.anyMatch(botName -> userAgent.indexOf(botName) >= 0));
444 if (!isBot) {
445 searchLog.getUserInfo().ifPresent(userInfo -> {
446 final String code = userInfo.getId();
447 final UserInfo oldUserInfo = userInfoMap.get(code);
448 if (oldUserInfo != null) {
449 userInfo.setCreatedAt(oldUserInfo.getCreatedAt());
450 }
451 userInfoMap.put(code, userInfo);
452 });
453 searchLogList.add(searchLog);
454 }
455 }
456 if (searchLogList.size() >= batchSize) {
457 processUserInfoLog(searchLogList, userInfoMap);
458 processSearchLog(searchLogList);
459 searchLogList.clear();
460 userInfoMap.clear();
461 }
462 }
463
464 if (!searchLogList.isEmpty()) {
465 processUserInfoLog(searchLogList, userInfoMap);
466 processSearchLog(searchLogList);
467 }
468 }
469
470
471
472
473
474
475 protected void processSearchLog(final List<SearchLog> searchLogList) {
476 if (!searchLogList.isEmpty()) {
477 final FessConfig fessConfig = ComponentUtil.getFessConfig();
478
479 if (fessConfig.isLoggingSearchUseLogfile()) {
480 searchLogList.forEach(this::writeSearchLogEvent);
481 }
482
483 storeSearchLogList(searchLogList);
484
485 if (fessConfig.isSuggestSearchLog()) {
486 final SuggestHelper suggestHelper = ComponentUtil.getSuggestHelper();
487 suggestHelper.indexFromSearchLog(searchLogList);
488 }
489 }
490 }
491
492
493
494
495
496
497
498 protected void processUserInfoLog(final List<SearchLog> searchLogList, final Map<String, UserInfo> userInfoMap) {
499 if (!userInfoMap.isEmpty()) {
500 final FessConfig fessConfig = ComponentUtil.getFessConfig();
501 final List<UserInfo> insertList = new ArrayList<>(userInfoMap.values());
502 final List<UserInfo> updateList = new ArrayList<>();
503 final UserInfoBhv userInfoBhv = ComponentUtil.getComponent(UserInfoBhv.class);
504 userInfoBhv.selectList(cb -> {
505 cb.query().setId_InScope(userInfoMap.keySet());
506 cb.fetchFirst(userInfoMap.size());
507 }).forEach(userInfo -> {
508 final String code = userInfo.getId();
509 final UserInfo entity = userInfoMap.get(code);
510 entity.setId(userInfo.getId());
511 entity.setCreatedAt(userInfo.getCreatedAt());
512 updateList.add(entity);
513 insertList.remove(entity);
514 });
515
516 if (fessConfig.isLoggingSearchUseLogfile()) {
517 insertList.forEach(this::writeSearchLogEvent);
518 updateList.forEach(this::writeSearchLogEvent);
519 }
520
521 userInfoBhv.batchInsert(insertList);
522 userInfoBhv.batchUpdate(updateList);
523
524 searchLogList.stream().forEach(searchLog -> {
525 searchLog.getUserInfo().ifPresent(userInfo -> {
526 searchLog.setUserInfoId(userInfo.getId());
527 });
528 });
529 }
530 }
531
532
533
534
535
536
537 protected void storeSearchLogList(final List<SearchLog> searchLogList) {
538 final SearchLogBhv searchLogBhv = ComponentUtil.getComponent(SearchLogBhv.class);
539 searchLogBhv.batchUpdate(searchLogList, op -> {
540 op.setRefreshPolicy(Constants.TRUE);
541 });
542 }
543
544
545
546
547
548
549 protected void processClickLogQueue(final Queue<ClickLog> queue) {
550 final FessConfig fessConfig = ComponentUtil.getFessConfig();
551 final int batchSize = fessConfig.getSearchlogProcessBatchSizeAsInteger();
552 final Map<String, Integer> clickCountMap = new HashMap<>();
553 final List<ClickLog> clickLogList = new ArrayList<>();
554 while (!queue.isEmpty()) {
555 final ClickLog clickLog = queue.poll();
556 if (clickLog != null) {
557 try {
558 final SearchLogBhv searchLogBhv = ComponentUtil.getComponent(SearchLogBhv.class);
559 searchLogBhv.selectEntity(cb -> {
560 cb.query().setQueryId_Equal(clickLog.getQueryId());
561 }).ifPresent(entity -> {
562 clickLogList.add(clickLog);
563 final String docId = clickLog.getDocId();
564 Integer countObj = clickCountMap.get(docId);
565 if (countObj == null) {
566 countObj = 1;
567 } else {
568 countObj = countObj.intValue() + 1;
569 }
570 clickCountMap.put(docId, countObj);
571 }).orElse(() -> {
572 logger.warn("Not Found for SearchLog: {}", clickLog);
573 });
574 } catch (final Exception e) {
575 logger.warn("Failed to process: {}", clickLog, e);
576 }
577 }
578 if (clickLogList.size() >= batchSize) {
579 processClickLog(clickLogList);
580 updateClickFieldInIndex(clickCountMap);
581 clickLogList.clear();
582 clickCountMap.clear();
583 }
584 }
585
586 if (!clickLogList.isEmpty()) {
587 processClickLog(clickLogList);
588 updateClickFieldInIndex(clickCountMap);
589 }
590 }
591
592
593
594
595
596
597 protected void updateClickFieldInIndex(final Map<String, Integer> clickCountMap) {
598 if (!clickCountMap.isEmpty()) {
599 final SearchHelper searchHelper = ComponentUtil.getSearchHelper();
600 final FessConfig fessConfig = ComponentUtil.getFessConfig();
601 try {
602 final UpdateRequest[] updateRequests =
603 searchHelper
604 .getDocumentListByDocIds(clickCountMap.keySet().toArray(new String[clickCountMap.size()]),
605 new String[] { fessConfig.getIndexFieldDocId(), fessConfig.getIndexFieldLang() },
606 OptionalThing.of(FessUserBean.empty()), SearchRequestType.ADMIN_SEARCH)
607 .stream()
608 .map(doc -> {
609 final String id = DocumentUtil.getValue(doc, fessConfig.getIndexFieldId(), String.class);
610 final String docId = DocumentUtil.getValue(doc, fessConfig.getIndexFieldDocId(), String.class);
611 if (id != null && docId != null && clickCountMap.containsKey(docId)) {
612 final Integer count = clickCountMap.get(docId);
613 final Script script = ComponentUtil.getLanguageHelper()
614 .createScript(doc,
615 "ctx._source." + fessConfig.getIndexFieldClickCount() + "+=" + count.toString());
616 final Map<String, Object> upsertMap = new HashMap<>();
617 upsertMap.put(fessConfig.getIndexFieldClickCount(), count);
618 return new UpdateRequest(fessConfig.getIndexDocumentUpdateIndex(), id).script(script)
619 .upsert(upsertMap);
620 }
621 return null;
622 })
623 .filter(req -> req != null)
624 .toArray(n -> new UpdateRequest[n]);
625 if (updateRequests.length > 0) {
626 searchHelper.bulkUpdate(builder -> {
627 for (final UpdateRequest req : updateRequests) {
628 builder.add(req);
629 }
630 });
631 }
632 } catch (final Exception e) {
633 logger.warn("Failed to update clickCounts", e);
634 }
635 }
636 }
637
638
639
640
641
642
643 protected void processClickLog(final List<ClickLog> clickLogList) {
644 if (!clickLogList.isEmpty()) {
645 final FessConfig fessConfig = ComponentUtil.getFessConfig();
646 if (fessConfig.isLoggingSearchUseLogfile()) {
647 clickLogList.forEach(this::writeSearchLogEvent);
648 }
649 try {
650 ComponentUtil.getComponent(ClickLogBhv.class).batchInsert(clickLogList);
651 } catch (final Exception e) {
652 logger.warn("Failed to insert: {}", clickLogList, e);
653 }
654 }
655 }
656
657
658
659
660
661
662 public void writeSearchLogEvent(final SearchLogEvent event) {
663 try {
664 final Map<String, Object> source = toSource(event);
665 searchLogLogger.info(objectMapper.writeValueAsString(source));
666 } catch (final JsonProcessingException e) {
667 logger.warn("Failed to write {}", event, e);
668 }
669 }
670
671
672
673
674
675
676
677 protected Map<String, Object> toSource(final SearchLogEvent searchLogEvent) {
678 final Map<String, Object> source = toLowerHyphen(searchLogEvent.toSource());
679 source.put("_id", searchLogEvent.getId());
680
681 source.put("event_type", searchLogEvent.getEventType());
682 return source;
683 }
684
685
686
687
688
689
690
691 protected Map<String, Object> toLowerHyphen(final Map<String, Object> source) {
692 return source.entrySet()
693 .stream()
694 .collect(Collectors.toMap(e -> CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, e.getKey()), e -> {
695 final Object value = e.getValue();
696 if (value instanceof Map) {
697 @SuppressWarnings("unchecked")
698 final Map<String, Object> mapValue = (Map<String, Object>) value;
699 return toLowerHyphen(mapValue);
700 }
701 return e.getValue();
702 }));
703 }
704
705
706
707
708
709
710 public void setUserCheckInterval(final long userCheckInterval) {
711 this.userCheckInterval = userCheckInterval;
712 }
713
714
715
716
717
718
719 public void setUserInfoCacheSize(final int userInfoCacheSize) {
720 this.userInfoCacheSize = userInfoCacheSize;
721 }
722
723
724
725
726
727
728 public void setLoggerName(final String loggerName) {
729 this.loggerName = loggerName;
730 }
731 }