1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 }