Skip to content

Commit

Permalink
Fix #9177 dump JVM info (#11845)
Browse files Browse the repository at this point in the history
Fix #9177 dump info from Runtime, Jetty.VERSION and System.getProperties
  • Loading branch information
gregw authored May 28, 2024
1 parent 7e36f3c commit 0425828
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.eclipse.jetty.util.component.ClassLoaderDump;
import org.eclipse.jetty.util.component.DumpableAttributes;
import org.eclipse.jetty.util.component.DumpableCollection;
import org.eclipse.jetty.util.component.DumpableMap;
import org.eclipse.jetty.util.component.Environment;
import org.eclipse.jetty.util.component.Graceful;
import org.eclipse.jetty.util.component.LifeCycle;
Expand Down Expand Up @@ -137,6 +138,7 @@ public Server(@Name("address") InetSocketAddress addr)
public Server(@Name("threadPool") ThreadPool pool)
{
this(pool, null, null);
installBean(new DumpableMap("System Properties", System.getProperties()));
}

public Server(@Name("threadPool") ThreadPool threadPool, @Name("scheduler") Scheduler scheduler, @Name("bufferPool") ByteBufferPool bufferPool)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.Blocker;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.thread.Invocable;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -143,6 +145,26 @@ public boolean handle(Request request, Response response, Callback callback)
assertThat(response.getContent(), is("Hello"));
}

@Test
public void testDump() throws Exception
{
testSimpleGET();
((QueuedThreadPool)(_server.getThreadPool())).tryExecute(() -> {});
String dump = _server.dump();
assertThat(dump, containsString("oejs.Server@"));
assertThat(dump, containsString("QueuedThreadPool"));
assertThat(dump, containsString("+= ReservedThreadExecutor@"));
assertThat(dump, containsString(".ArrayByteBufferPool@"));
assertThat(dump, containsString("+- System Properties size="));
assertThat(dump, containsString("+> java.home: "));
assertThat(dump, containsString("+> java.runtime.version: "));
assertThat(dump, containsString("+= oejsh.ContextHandler@"));
assertThat(dump, containsString("+= LocalConnector@"));
assertThat(dump, containsString("key: +-"));
assertThat(dump, containsString("JVM: "));
assertThat(dump, containsString(Jetty.VERSION));
}

public static Stream<Arguments> completionScenarios()
{
List<Arguments> arguments = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -745,10 +745,10 @@ public void dumpStdErr()
{
try
{
dump(System.err, "");
System.err.println(Dumpable.KEY);
Dumpable.dump(this, System.err);
System.err.println();
}
catch (IOException e)
catch (Throwable e)
{
LOG.warn("Unable to dump", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,21 @@
package org.eclipse.jetty.util.component;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.Array;
import java.nio.file.Path;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.annotation.ManagedObject;
Expand All @@ -31,7 +37,7 @@
@ManagedObject("Dumpable Object")
public interface Dumpable
{
String KEY = "key: +- bean, += managed, +~ unmanaged, +? auto, +: iterable, +] array, +@ map, +> undefined";
String KEY = "key: +- bean, += managed, +~ unmanaged, +? auto, +: iterable, +] array, +@ map, +> undefined\n";

@ManagedOperation(value = "Dump the nested Object state as a String", impact = "INFO")
default String dump()
Expand All @@ -50,24 +56,55 @@ default String dump()
void dump(Appendable out, String indent) throws IOException;

/**
* Utility method to implement {@link #dump()} by calling {@link #dump(Appendable, String)}
* Utility method to dump to a {@link String}
*
* @param dumpable The dumpable to dump
* @return The dumped string
* @see #dump(Appendable, String)
*/
static String dump(Dumpable dumpable)
{
StringBuilder b = new StringBuilder();
dump(dumpable, b);
return b.toString();
}

/**
* Utility method to dump to an {@link Appendable}
*
* @param dumpable The dumpable to dump
* @param out The destination of the dump
*/
static void dump(Dumpable dumpable, Appendable out)
{
try
{
dumpable.dump(b, "");
dumpable.dump(out, "");

out.append(KEY);
Runtime runtime = Runtime.getRuntime();
Instant now = Instant.now();
String zone = System.getProperty("user.timezone");
out.append("JVM: %s %s %s; OS: %s %s %s; Jetty: %s; CPUs: %d; mem(free/total/max): %,d/%,d/%,d MiB\nUTC: %s; %s: %s".formatted(
System.getProperty("java.vm.vendor"),
System.getProperty("java.vm.name"),
System.getProperty("java.vm.version"),
System.getProperty("os.name"),
System.getProperty("os.arch"),
System.getProperty("os.version"),
Jetty.VERSION,
runtime.availableProcessors(),
runtime.freeMemory() / (1024 * 1024),
runtime.totalMemory() / (1024 * 1024),
runtime.maxMemory() / (1024 * 1024),
DateTimeFormatter.ISO_DATE_TIME.format(now.atOffset(ZoneOffset.UTC)),
zone,
DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(now.atZone(ZoneId.of(zone)))));
}
catch (IOException e)
{
b.append(e.toString());
throw new UncheckedIOException(e);
}
b.append(KEY);
return b.toString();
}

/**
Expand Down Expand Up @@ -301,7 +338,7 @@ public void dump(Appendable out, String indent) throws IOException
* interface to allow it to refine which of its beans can be
* dumped.
*/
public interface DumpableContainer extends Dumpable
interface DumpableContainer extends Dumpable
{
default boolean isDumpable(Object o)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.util.component;

import java.io.IOException;
import java.util.Comparator;
import java.util.Map;

public class DumpableMap implements Dumpable
{
private final String _name;
private final Map<?, ?> _map;

public DumpableMap(String name, Map<?, ?> map)
{
_name = name;
_map = map;
}

@Override
public void dump(Appendable out, String indent) throws IOException
{
Object[] array = _map.entrySet().stream()
.sorted(Map.Entry.comparingByKey(Comparator.comparing(String::valueOf)))
.map(e -> Dumpable.named(String.valueOf(e.getKey()), e.getValue())).toArray(Object[]::new);
Dumpable.dumpObjects(out, indent, _name + " size=" + array.length, array);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.eclipse.jetty.util.ProcessorUtils;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.component.DumpableCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -236,8 +235,12 @@ public void dump(Appendable out, String indent) throws IOException
int capacity = capacity();
List<Object> slots = new ArrayList<>(capacity);
for (int i = 0; i < capacity; i++)
slots.add(_items.get(toSlot(i)));
Dumpable.dumpObjects(out, indent, this, new DumpableCollection("items", slots));
{
E slot = _items.get(toSlot(i));
if (slot != null)
slots.add(Dumpable.named(Integer.toString(i), slot));
}
Dumpable.dumpObjects(out, indent, this, slots.toArray());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -833,8 +833,7 @@ public void testDump() throws Exception
assertThat(count(dump, " - STARTED"), is(3));
assertThat(dump, containsString(",3<=3<=4,i=1,r=2,"));
assertThat(dump, containsString("[ReservedThreadExecutor@"));
assertThat(count(dump, "> ReservedThread@"), is(1));
assertThat(count(dump, "> null"), is(1));
assertThat(count(dump, "+> 0: ReservedThread@"), is(1));
assertThat(count(dump, "QueuedThreadPoolTest.lambda$testDump$"), is(0));

pool.setDetailedDump(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,12 @@ public void contextInitialized(ServletContextEvent sce)
if (_out == null)
{
handler.dumpStdErr();
System.err.println(Dumpable.KEY);
}
else
{
try
{
handler.dump(_out);
_out.println(Dumpable.KEY);
Dumpable.dump(handler, _out);
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,12 @@ public void contextInitialized(ServletContextEvent sce)
if (_out == null)
{
handler.dumpStdErr();
System.err.println(Dumpable.KEY);
}
else
{
try
{
handler.dump(_out);
_out.println(Dumpable.KEY);
Dumpable.dump(handler, _out);
}
catch (Exception e)
{
Expand Down

0 comments on commit 0425828

Please sign in to comment.