Skip to content
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

Use java.time.Instant to get micros accurate timestamps #261

Merged
merged 4 commits into from
Oct 29, 2018

Conversation

felixbarny
Copy link
Member

fall back to System.currentTimeMillis() for Java 7

@codecov-io
Copy link

codecov-io commented Oct 27, 2018

Codecov Report

Merging #261 into master will increase coverage by 0.07%.
The diff coverage is 90.9%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #261      +/-   ##
============================================
+ Coverage     72.96%   73.04%   +0.07%     
  Complexity     1134     1134              
============================================
  Files           121      122       +1     
  Lines          4221     4240      +19     
  Branches        422      422              
============================================
+ Hits           3080     3097      +17     
- Misses          943      945       +2     
  Partials        198      198
Impacted Files Coverage Δ Complexity Δ
...o/elastic/apm/impl/transaction/EpochTickClock.java 100% <100%> (ø) 7 <2> (ø) ⬇️
...a/co/elastic/apm/impl/transaction/SystemClock.java 89.47% <89.47%> (ø) 0 <0> (?)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7da2e91...f04e2f9. Read the comment docs.

Copy link
Contributor

@eyalkoren eyalkoren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to avoid referencing Java 8 types and opt for reflection instead, otherwise you are dependent on JVM implementation of class linkage.

import java.time.Clock;
import java.time.Instant;

public interface SystemClock {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's mark with a TODO or something that will let us quickly find all places we can cut unnecessary code when dropping support to 1.7.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We just have to look out for the usages of the @IgnoreJRERequirement annotation. The animal sniffer maven plugin would not let us verify non-Java 7 code which is not annotated with this annotation.

final long epochMillis = System.currentTimeMillis();
epochTickClock.init(epochMillis, 0);
final long epochMicros = SystemClock.ForJava8CapableVM.INSTANCE.getEpochMicros();
epochTickClock.init(epochMicros, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unit-test JRE 7 code as well (regardless of the actual JRE running the tests)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

enum ForJava8CapableVM implements SystemClock {
INSTANCE;

private static final Clock clock = Clock.systemUTC();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be risky - this class cannot be fully loaded (pass linkage phase) on JRE 7. This means that ForCurrentVM cannot be fully linked as well as it depends on it. You may not experience any problem using a lazy-linkage JVM, one that allows only linking parts of the class's constant pool when required, but I am not sure it is safe to assume that will be the case in all JVMs as I don't think the lazy-linkage is part of the JVM spec.
Using reflection referencing a Method or MethodHandle would be a safer approach

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are completely right - that would be safer. But we don't support such a VM so I would not want to pay the cost of the increased complexity and potentially higher overhead yet. We can't claim to support a particular VM if we don't have an integration test for it. If we are to support such a VM in the future at that time, we might even have already dropped Java 7 support so that we can just use Instant right away.

@felixbarny
Copy link
Member Author

Sorry for not laying out the motivation of this change. With the current approach, the timestamp can be up to 1ms off, as it just uses System.currentTimeMillis() * 1_000 for the transaction timestamp.

This can lead to misaligned spans in the UI:
screen shot 2018-10-29 at 08 30 04

Go is using an accurate epoch micros timestamp but the Java agent sort of truncates the timestamp to milliseconds. When making calls across different hosts, the clocks can be misaligned by serveral milliseconds and the UI has to do compensating actions anyway, but at least when making calls on the same host, the timestamps should be consistent.

@eyalkoren
Copy link
Contributor

Yeah, only read through the conversation today, so removed the comment on "thinking it is too early to use Java 8 stuff" :)

@felixbarny felixbarny merged commit c6b43e1 into elastic:master Oct 29, 2018
@felixbarny felixbarny deleted the microsecond-accurate-timestamps branch October 29, 2018 09:34
@felixbarny felixbarny self-assigned this Oct 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants