View Javadoc
1   /*
2    * Copyright 2012-2021 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.timer;
17  
18  import java.io.ByteArrayOutputStream;
19  import java.io.OutputStream;
20  import java.util.Arrays;
21  import java.util.List;
22  import java.util.function.Supplier;
23  import java.util.stream.Collectors;
24  
25  import org.apache.commons.text.StringEscapeUtils;
26  import org.apache.logging.log4j.LogManager;
27  import org.apache.logging.log4j.Logger;
28  import org.codelibs.core.timer.TimeoutTarget;
29  import org.codelibs.fesen.action.admin.cluster.node.stats.NodesStatsResponse;
30  import org.codelibs.fesen.common.xcontent.ToXContent;
31  import org.codelibs.fesen.common.xcontent.XContentBuilder;
32  import org.codelibs.fesen.common.xcontent.XContentFactory;
33  import org.codelibs.fesen.monitor.jvm.JvmStats;
34  import org.codelibs.fesen.monitor.jvm.JvmStats.BufferPool;
35  import org.codelibs.fesen.monitor.jvm.JvmStats.Classes;
36  import org.codelibs.fesen.monitor.jvm.JvmStats.GarbageCollectors;
37  import org.codelibs.fesen.monitor.jvm.JvmStats.Mem;
38  import org.codelibs.fesen.monitor.jvm.JvmStats.Threads;
39  import org.codelibs.fesen.monitor.os.OsProbe;
40  import org.codelibs.fesen.monitor.os.OsStats;
41  import org.codelibs.fesen.monitor.process.ProcessProbe;
42  import org.codelibs.fess.Constants;
43  import org.codelibs.fess.es.client.SearchEngineClient;
44  import org.codelibs.fess.util.ComponentUtil;
45  
46  public class SystemMonitorTarget implements TimeoutTarget {
47      private static final Logger logger = LogManager.getLogger(SystemMonitorTarget.class);
48  
49      protected StringBuilder append(final StringBuilder buf, final String key, final Supplier<Object> supplier) {
50          buf.append('"').append(key).append("\":");
51          try {
52              final Object value = supplier.get();
53              if (value == null) {
54                  buf.append("null");
55              } else if ((value instanceof Integer) || (value instanceof Long)) {
56                  buf.append((value));
57              } else if (value instanceof Short) {
58                  buf.append(((Short) value).shortValue());
59              } else if (value instanceof double[]) {
60                  buf.append(Arrays.toString((double[]) value));
61              } else {
62                  buf.append('"').append(StringEscapeUtils.escapeJson(value.toString())).append('"');
63              }
64          } catch (final Exception e) {
65              buf.append("null");
66          }
67          return buf;
68      }
69  
70      @Override
71      public void expired() {
72          final StringBuilder buf = new StringBuilder(1000);
73  
74          buf.append("[SYSTEM MONITOR] ");
75          buf.append('{');
76  
77          appendOsStats(buf);
78          appendProcessStats(buf);
79          appendJvmStats(buf);
80          appendFesenStats(buf);
81  
82          append(buf, "timestamp", System::currentTimeMillis);
83          buf.append('}');
84  
85          logger.info(buf.toString());
86      }
87  
88      private void appendJvmStats(final StringBuilder buf) {
89          buf.append("\"jvm\":{");
90          final JvmStats jvmStats = JvmStats.jvmStats();
91          final Mem mem = jvmStats.getMem();
92          buf.append("\"memory\":{");
93          buf.append("\"heap\":{");
94          append(buf, "used", () -> mem.getHeapUsed().getBytes()).append(',');
95          append(buf, "committed", () -> mem.getHeapCommitted().getBytes()).append(',');
96          append(buf, "max", () -> mem.getHeapMax().getBytes()).append(',');
97          append(buf, "percent", () -> mem.getHeapUsedPercent());
98          buf.append("},");
99          buf.append("\"non_heap\":{");
100         append(buf, "used", () -> mem.getNonHeapUsed().getBytes()).append(',');
101         append(buf, "committed", () -> mem.getNonHeapCommitted().getBytes());
102         buf.append('}');
103         buf.append("},");
104         final List<BufferPool> bufferPools = jvmStats.getBufferPools();
105         buf.append("\"pools\":{");
106         buf.append(bufferPools.stream().map(p -> {
107             final StringBuilder b = new StringBuilder();
108             b.append('"').append(StringEscapeUtils.escapeJson(p.getName())).append("\":{");
109             append(b, "count", () -> p.getCount()).append(',');
110             append(b, "used", () -> p.getUsed().getBytes()).append(',');
111             append(b, "capacity", () -> p.getTotalCapacity().getBytes()).append('}');
112             return b.toString();
113         }).collect(Collectors.joining(",")));
114         buf.append("},");
115         final GarbageCollectors gc = jvmStats.getGc();
116         buf.append("\"gc\":{");
117         buf.append(Arrays.stream(gc.getCollectors()).map(c -> {
118             final StringBuilder b = new StringBuilder();
119             b.append('"').append(StringEscapeUtils.escapeJson(c.getName())).append("\":{");
120             append(b, "count", () -> c.getCollectionCount()).append(',');
121             append(b, "time", () -> c.getCollectionTime().getMillis()).append('}');
122             return b.toString();
123         }).collect(Collectors.joining(",")));
124         buf.append("},");
125         final Threads threads = jvmStats.getThreads();
126         buf.append("\"threads\":{");
127         append(buf, "count", () -> threads.getCount()).append(',');
128         append(buf, "peak", () -> threads.getPeakCount());
129         buf.append("},");
130         final Classes classes = jvmStats.getClasses();
131         buf.append("\"classes\":{");
132         append(buf, "loaded", () -> classes.getLoadedClassCount()).append(',');
133         append(buf, "total_loaded", () -> classes.getTotalLoadedClassCount()).append(',');
134         append(buf, "unloaded", () -> classes.getUnloadedClassCount());
135         buf.append("},");
136         append(buf, "uptime", () -> jvmStats.getUptime().getMillis());
137         buf.append("},");
138     }
139 
140     private void appendProcessStats(final StringBuilder buf) {
141         buf.append("\"process\":{");
142         final ProcessProbe processProbe = ProcessProbe.getInstance();
143         buf.append("\"file_descriptor\":{");
144         append(buf, "open", () -> processProbe.getOpenFileDescriptorCount()).append(',');
145         append(buf, "max", () -> processProbe.getMaxFileDescriptorCount());
146         buf.append("},");
147         buf.append("\"cpu\":{");
148         append(buf, "percent", () -> processProbe.getProcessCpuPercent()).append(',');
149         append(buf, "total", () -> processProbe.getProcessCpuTotalTime());
150         buf.append("},");
151         buf.append("\"virtual_memory\":{");
152         append(buf, "total", () -> processProbe.getTotalVirtualMemorySize());
153         buf.append('}');
154         buf.append("},");
155     }
156 
157     private void appendOsStats(final StringBuilder buf) {
158         buf.append("\"os\":{");
159         final OsProbe osProbe = OsProbe.getInstance();
160         buf.append("\"memory\":{");
161         buf.append("\"physical\":{");
162         append(buf, "free", () -> osProbe.getFreePhysicalMemorySize()).append(',');
163         append(buf, "total", () -> osProbe.getTotalPhysicalMemorySize());
164         buf.append("},");
165         buf.append("\"swap_space\":{");
166         append(buf, "free", () -> osProbe.getFreeSwapSpaceSize()).append(',');
167         append(buf, "total", () -> osProbe.getTotalSwapSpaceSize());
168         buf.append('}');
169         buf.append("},");
170         buf.append("\"cpu\":{");
171         append(buf, "percent", () -> osProbe.getSystemCpuPercent());
172         final OsStats osStats = osProbe.osStats();
173         buf.append("},");
174         append(buf, "load_averages", () -> osStats.getCpu().getLoadAverage());
175         buf.append("},");
176     }
177 
178     private void appendFesenStats(final StringBuilder buf) {
179         String stats = null;
180         try {
181             final SearchEngineClient esClient = ComponentUtil.getSearchEngineClient();
182             final NodesStatsResponse response = esClient.admin().cluster().prepareNodesStats().all().execute().actionGet(10000L);
183             final XContentBuilder builder = XContentFactory.jsonBuilder();
184             builder.startObject();
185             response.toXContent(builder, ToXContent.EMPTY_PARAMS);
186             builder.endObject();
187             builder.flush();
188             try (OutputStream out = builder.getOutputStream()) {
189                 stats = ((ByteArrayOutputStream) out).toString(Constants.UTF_8);
190             }
191         } catch (final Exception e) {
192             logger.debug("Failed to access Fesen stats.", e);
193         }
194         buf.append("\"elasticsearch\":").append(stats).append(',');
195     }
196 }