New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
System start date #877
Comments
It's possible to add that, but I have a long list of other things I'd like to do first. Can you contribute a PR? |
I'd like to contribute here. Quick question for clarification...Is this system start date in reference to the date the system last started? And, if that's the right Date Time being referenced here....return ms, ns, or seconds and let the caller determine what to do? |
just get the up time and subtract. Note on that windows 10 and other os's with a hybrid sleep/shutdown, the dates might not be what you expect |
Hello, Please find my contribution public final class SystemUtil {
private static final Pattern MAC_UNIX_PATTERN = Pattern.compile("((\\d+) days,)? (\\d+):(\\d+)");
private static final Object LOCK_GETSYSTEMUPTIME = new Object();
private static final List<String[]> LINUX_COMMANDS = Arrays.asList(new String[] { "who", "-b" }, new String[] { "last reboot | less" }, new String[] { "uptime", "-s" });
private static String systemUptime;
private SystemUtil() {
super();
}
public static String getSystemUptime() throws IOException {
synchronized (LOCK_GETSYSTEMUPTIME) {
if (systemUptime == null) {
if (SystemUtils.IS_OS_WINDOWS) {
systemUptime = SystemUtil.getSystemUptimeWindows();
} else if (SystemUtils.IS_OS_UNIX) {
systemUptime = SystemUtil.getSystemUptimeUnix();
} else if (SystemUtils.IS_OS_MAC) {
systemUptime = SystemUtil.getSystemUptimeCommonUnixAndMac();
}
systemUptime = StringUtils.trimToNull(systemUptime);
}
}
Validate.notBlank(systemUptime, "A ce stade systemUptime ne peut pas être null");
return systemUptime;
}
private static String getSystemUptimeWindows() throws IOException {
return SystemUtil.executeCommands("wmic", "OS", "Get", "LastBootUpTime");
}
private static String getSystemUptimeUnix() throws IOException {
String res = null;
for (final String[] commands : LINUX_COMMANDS) {
try {
res = SystemUtil.executeCommands(commands);
if (StringUtils.isNotBlank(res)) {
break;
}
} catch (final IOException ioException) {
// Not available command
}
}
if (StringUtils.isBlank(res)) {
res = SystemUtil.getSystemUptimeCommonUnixAndMac();
}
return res;
}
private static String getSystemUptimeCommonUnixAndMac() throws IOException {
String res = null;
final Calendar calendar = Calendar.getInstance();
final String result = SystemUtil.executeCommands("uptime");
// Sample linux 'uptime' command :
// 10:37:04 up 17:51, load average: 0.23, 0.88, 0.89
// 10:38:42 up 17:53, load average: 0.70, 0.81, 0.86
// 10:28:21 up 189 days, 19:00, 1 user, load average: 0.07, 0.13, 0.16
// 08:11:22 up 146 days, 34 min, 3 users, load average: 0.28, 0.45, 0.38
if (StringUtils.isNotBlank(result)) {
final Matcher matcher = MAC_UNIX_PATTERN.matcher(result);
if (matcher.find()) {
final int days = NumberUtils.toInt(matcher.group(2));
final int hours = NumberUtils.toInt(matcher.group(3));
final int minutes = NumberUtils.toInt(matcher.group(4));
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
calendar.add(Calendar.DAY_OF_MONTH, -1 * days);
calendar.add(Calendar.HOUR_OF_DAY, -1 * hours);
calendar.add(Calendar.MINUTE, -1 * minutes);
res = String.valueOf(calendar.getTimeInMillis());
}
}
return res;
}
private static String executeCommands(final String... commands) throws IOException {
Validate.notEmpty(commands, "commands cannot be empty");
final Process uptimeProc;
if (commands.length == 1) {
uptimeProc = Runtime.getRuntime().exec(commands[0]);
} else {
uptimeProc = Runtime.getRuntime().exec(commands);
}
try {
final int exitCode = uptimeProc.waitFor();
if (exitCode != 0) {
throw new IOException("Command exited with " + exitCode);
}
} catch (final InterruptedException interruptedException) {
throw new IOException(interruptedException);
}
String result = null;
try (InputStream inputStream = uptimeProc.getInputStream();
Reader inputStreamReader = new InputStreamReader(inputStream, Charset.defaultCharset());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) {
String lastLine = null;
String line;
while ((line = bufferedReader.readLine()) != null) {
if (StringUtils.isNotBlank(line)) {
lastLine = line.trim();
}
}
if (lastLine != null) {
result = lastLine;
}
}
return StringUtils.trimToNull(result);
}
} It is strange but on unix system, not seems to always return the same date. Not tested on mac. |
@tbradellis Since this is a new functionality, we get to describe what it is! Putting it the same units as the existing "up time" seems reasonable to me. @spyhunter99 "Use @jflefebvre06 thanks for the code! There are a few changes you need to make. It would be great if you can put together a PR and submit the code there. You want to:
|
I see! Thanks @dbwiddis. Looks like @jflefebvre06 has put some effort in here so I'll look for something else to work on unless @jflefebvre06 decides otherwise. |
Hey @jflefebvre06 are you planning on submitting a PR or can @tbradellis take over? :) |
Based on this StackOverflow post, using WMI boot time is a bad idea. Subtracting up time from current time seems the best option -- that's what we do in |
Here's the code to read the boot up time from the event log. Reading the log iterating backwards takes 238ms vs. reading it forwards at 410ms... still kinda long.
Another note: the |
Here's some runtime comparisons of the options:
I kind of like the last one, with simple subtraction, but unfortunately it appears that it loses a lot of time with sleep/hibernate cycles. It's at least close to the WMI time. The Event Log time is probably the most accurate, though, if we can afford the longer (229 ms) read time. |
More fun. Event ID 12 is actually the OS start up time, but doesn't always occur if Windows "Fast Startup" is enabled. So the strategy should be to check for event id's 6005 or 12. When iterating backwards, find the first 6005; if a 12 exists before the next 6005, use it; otherwise use the first 6005. |
Here's my recommended code for Windows. Runs in about 200ms.
|
@tbradellis This looks like no one else is going to do it, do you want to tackle it? |
Hello On windows it does not work.
systemBootDate value is 'Wed Oct 09 15:54:18 CEST 2019' My computer is a Windows 7 French. |
Was it a full system boot or a reboot/wake from sleep? OSHI reads the event log. What system events happened at 07:30? |
Sorry not 07:30 but 07:54, I m wake up not early today :) Nom du journal :System <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-Kernel-General" Guid="{A68CA8B7-004F-D7B6-A698-07E2DE0F1F5D}" />
<EventID>12</EventID>
<Version>0</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="2019-10-10T05:54:41.687200300Z" />
<EventRecordID>1424860</EventRecordID>
<Correlation />
<Execution ProcessID="4" ThreadID="8" />
<Channel>System</Channel>
<Computer>ITEM-66489.XXX</Computer>
<Security UserID="S-1-5-18" />
</System>
<EventData>
<Data Name="MajorVersion">6</Data>
<Data Name="MinorVersion">1</Data>
<Data Name="BuildVersion">7601</Data>
<Data Name="QfeVersion">24441</Data>
<Data Name="ServiceVersion">1</Data>
<Data Name="BootMode">0</Data>
<Data Name="StartTime">2019-10-10T05:54:41.125599400Z</Data>
</EventData>
</Event> |
07:54:41 for a boot time (event 12) should be what OSHI captures. And given that your Looking at the code I can't see a problem with the assignment of boot time from the event log record, but it's possible that it's using the fallback calculation of "now minus uptime". Looking carefully at the logic it seems to require we find an event 6005 before (chronologically "after") the event 12, per my comment above:
It seems the case isn't handled where we have a 12 but no 6005. So that's one bug. The other bug may be in the calculation of UpTime... has your system been hibernating for about 7 hours? If so this is probably not the issue... |
hello @dbwiddis |
I have reboot my workstation at 17:18 Nom du journal :System <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-Kernel-General" Guid="{A68CA8B7-004F-D7B6-A698-07E2DE0F1F5D}" />
<EventID>12</EventID>
<Version>0</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="2019-10-10T15:18:01.718400400Z" />
<EventRecordID>1425242</EventRecordID>
<Correlation />
<Execution ProcessID="4" ThreadID="8" />
<Channel>System</Channel>
<Computer>ITEM-66489.dhcp.nice.fr.sopra</Computer>
<Security UserID="S-1-5-18" />
</System>
<EventData>
<Data Name="MajorVersion">6</Data>
<Data Name="MinorVersion">1</Data>
<Data Name="BuildVersion">7601</Data>
<Data Name="QfeVersion">24441</Data>
<Data Name="ServiceVersion">1</Data>
<Data Name="BootMode">0</Data>
<Data Name="StartTime">2019-10-10T15:18:01.125599400Z</Data>
</EventData>
</Event> And now oshi give System boot time 1570686885
|
OK, I did some testing on my own machine and have similar symptoms, identified by the bug I already identified.
You'll notice after your reboot (17:18) that OSHI identified the previous boot (7:54:45). (And in the one you just posted after this morning's new boot it got yesterday's 17:18 boot.) . The bug is that it's lagging a reboot behind in some cases. It appears in the event log that even though the "Event Log Service Startup" event (6005) occurs after the boot, these particular events are not necessarily reported in chronological order. In my event log, the Boot event (12) occurs first but is logged later. So the fix is to change the logic from identifying a 6005 "first" and then a 12... it needs to be robust to different ordering. |
Bug should be fixed in #1013, now in snapshot. (Re-)Closing this issue, re-open if you still have problems. |
Please find my test case below, not very fast but works fine @EnabledOnOs(OS.WINDOWS)
@Test
public void getSystemBootTimeTestWindows() {
final EventLogIterator iter = new EventLogIterator(null, "System", WinNT.EVENTLOG_BACKWARDS_READ);
final Optional<Long> time = StreamSupport.stream(Spliterators.spliteratorUnknownSize(iter, 0), true).filter(r -> r.getRecord().EventID.getLow().intValue() == 12)
.map(r -> r.getRecord().TimeGenerated.longValue()).max(Comparator.naturalOrder());
MatcherAssert.assertThat("Time found", time.isPresent());
MatcherAssert.assertThat("Is valid systemBootTime", SystemUtil.getSystemBootTime(), Matchers.equalTo(time.get()));
} |
Not fast because you read the entire event log to collect all the event 12s. :) Try enabling fast startup on Win10 and see if your test case still works... |
Yes I Know |
Hello,
Could you please add system start date ?
The text was updated successfully, but these errors were encountered: