How to trigger gauge only manually? - micrometer

I want to monitor a value from my database. This value could increase and decrease, so I use a gauge. I have no instance variable for this value, so I use a method reference instead of a object reference. The gauge calls this method automatically.
For performance reasons I don't want to call the method periodically. How can I trigger the gauge only on demand?
Code
#SpringBootApplication
public class TestApplication {
#Autowired private TestController testController;
#Autowired private MeterRegistry meterRegistry;
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Bean
public Gauge myGauge() {
return Gauge.builder("test_gauge", testController::calc).register(meterRegistry);
}
}
#RestController
#Slf4j
public class TestController {
public Double calc() {
// read value from database
Double d = RandomUtils.nextDouble();
log.info("Called with value {}", d);
return d;
}
#GetMapping(path = "/call")
public String call(#RequestParam(name = "value") Integer value) {
// save value to database
// trigger gauge
return "ok";
}
}
Logs
The method is called every 15 seconds when Prometheus is scraping the metrics.
2022-12-16 15:12:17.556 INFO 6260 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
2022-12-16 15:12:18.039 INFO 6260 --- [nio-8081-exec-1] test.TestController : Called with value 1.1228275083891679E306
2022-12-16 15:12:32.778 INFO 6260 --- [nio-8081-exec-2] test.TestController : Called with value 6.136924711044749E307
2022-12-16 15:12:44.798 INFO 6260 --- [nio-8081-exec-3] test.TestController : Called with value 4.914434799158517E307
2022-12-16 15:12:58.095 INFO 6260 --- [nio-8081-exec-5] test.TestController : Called with value 1.2183342676183758E308
Metric
The actuator endpoint prometheus returns the gauge metric.
# HELP test_gauge
# TYPE test_gauge gauge
test_gauge{application="test-service",} 1.2183342676183758E308

You can write a method that updates the value less frequently or on whatever trigger you want and return some default value or the old value.
E.g. only update the value if it is older than X:
AtomicLong lastCalculatedTime = new AtomicLong(0);
AtomicLong gaugeValue = new AtomicLong(0);
Gauge.builder("expensive", () -> {
long curr = System.nanoTime();
return gaugeValue.updateAndGet(old ->
lastCalculatedTime.updateAndGet(ts -> curr - ts > 10_000 ? curr : ts) == curr ? 0L /* new */ : old);
});

Related

Mockito (How to correctly mock nested objects)

I have this next class:
#Service
public class BusinessService {
#Autowired
private RedisService redisService;
private void count() {
String redisKey = "MyKey";
AtomicInteger counter = null;
if (!redisService.isExist(redisKey))
counter = new AtomicInteger(0);
else
counter = redisService.get(redisKey, AtomicInteger.class);
try {
counter.incrementAndGet();
redisService.set(redisKey, counter, false);
logger.info(String.format("Counter incremented by one. Current counter = %s", counter.get()));
} catch (JsonProcessingException e) {
logger.severe(String.format("Failed to increment counter."));
}
}
// Remaining code
}
and this this my RedisService.java class
#Service
public class RedisService {
private Logger logger = LoggerFactory.getLogger(RedisService.class);
#Autowired
private RedisConfig redisConfig;
#PostConstruct
public void postConstruct() {
try {
String redisURL = redisConfig.getUrl();
logger.info("Connecting to Redis at " + redisURL);
syncCommands = RedisClient.create(redisURL).connect().sync();
} catch (Exception e) {
logger.error("Exception connecting to Redis: " + e.getMessage(), e);
}
}
public boolean isExist(String redisKey) {
return syncCommands.exists(new String[] { redisKey }) == 1 ? true : false;
}
public <T extends Serializable> void set(String key, T object, boolean convertObjectToJson) throws JsonProcessingException {
if (convertObjectToJson)
syncCommands.set(key, writeValueAsString(object));
else
syncCommands.set(key, String.valueOf(object));
}
// Remaining code
}
and this is my test class
#Mock
private RedisService redisService;
#Spy
#InjectMocks
BusinessService businessService = new BusinessService();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void myTest() throws Exception {
for (int i = 0; i < 50; i++)
Whitebox.invokeMethod(businessService, "count");
// Remaining code
}
my problem is the counter always equals to one in logs when running tests
Counter incremented by one. Current counter = 1(printed 50 times)
and it should print:
Counter incremented by one. Current counter = 1
Counter incremented by one. Current counter = 2
...
...
Counter incremented by one. Current counter = 50
this means the Redis mock always passed as a new instance to BusinessService in each method call inside each loop, so how I can force this behavior to become only one instance used always for Redis inside the test method ??
Note: Above code is just a sample to explain my problem, but it's not a complete code.
Your conclusion that a new RedisService is somehow created in each iteration is wrong.
The problem is that it is a mock object for which you haven’t set any behaviours, so it responds with default values for each method call (null for objects, false for bools, 0 for ints etc).
You need to use Mockito.when to set behaviour on your mocks.
There is some additional complexity caused by the fact that:
you run the loop multiple times, and behaviour of the mocks differ between first and subsequent iterations
you create cached object in method under test. I used doAnswer to capture it.
You need to use doAnswer().when() instead of when().thenAnswer as set method returns void
and finally, atomicInt variable is modified from within the lambda. I made it a field of the class.
As the atomicInt is modified each time, I again used thenAnswer instead of thenReturn for get method.
class BusinessServiceTest {
#Mock
private RedisService redisService;
#InjectMocks
BusinessService businessService = new BusinessService();
AtomicInteger atomicInt = null;
#BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void myTest() throws Exception {
// given
Mockito.when(redisService.isExist("MyKey"))
.thenReturn(false)
.thenReturn(true);
Mockito.doAnswer((Answer<Void>) invocation -> {
atomicInt = invocation.getArgument(1);
return null;
}).when(redisService).set(eq("MyKey"), any(AtomicInteger.class), eq(false));
Mockito.when(redisService.get("MyKey", AtomicInteger.class))
.thenAnswer(invocation -> atomicInt);
// when
for (int i = 0; i < 50; i++) {
Whitebox.invokeMethod(businessService, "count");
}
// Remaining code
}
}
Having said that, I still find your code questionable.
You store AtomicInteger in Redis cache (by serializing it to String). This class is designed to be used by multiple threads in a process, and the threads using it the same counter need to share the same instance. By serializing it and deserializing on get, you are getting multiple instances of the (conceptually) same counter, which, to my eyes, looks like a bug.
smaller issue: You shouldn't normally test private methods
2 small ones: there is no need to instantiate the field annotated with #InjectMocks. You don't need #Spy as well.

Writing "WriteLine" message to trace window in Windows Workflow 4.5

I am using rehosted-designer of WF 4.5 to give an interface for the users to create a workflow with custom activities and some of the inbuilt activities of the framework.
I am using AsyncCodeActivity model (perfect fit for my requirement), and hence is bound to execute a workflow as below, i mean execution is triggered at once without the possibility to iterate the activities in the workflow:
WorkflowApplication wf = new WorkflowApplication(activeFlowChart);
............
............
var result = wf.BeginRun(null,null);
while (!result.IsCompleted)
{
Thread.Sleep(1);
continue;
}
wf.EndRun(result);
My workflow can have multiple "WriteLine" activities scattered in the workflow.
I want to retrieve the message of a particular "WriteLine" and show in the trace window as in the order how it appears in the workflow.
I have tried as below on completion, which displays all the "WriteLine" messages appended at the end of the execution:
wf.Extensions.Add(writer);
wf.Completed = arg =>
{
if (!string.IsNullOrEmpty(writer.ToString()))
{
//display
}
};
I am looking for a way to get the "WriteLine" message immediately when it occurs in the workflow, not on completion.
The below link helped me to think about writing custom TextWriter to solve the above usecase:
Redirecting Console.WriteLine() to Textbox
Instead of appending the characters to the "writer" object and print it to the display window when the workflow is completed (refer the code in my question), i wrote a custom TextWriter to print the message of each "WriteLine" activity when a new line("\r\n") is encountered. example below:
in constructor:
var writer = new WriteLineTextWriter(DisplayTraceMessage);
Console.SetOut(writer);
custom TextWriter:
public class WriteLineTextWriter : TextWriter
{
private Action<string, Brush> WriteTraceMessageToGUI { get; set; }
private StringBuilder line;
private byte counter;
public WriteLineTextWriter(Action<string, Brush> action)
{
WriteTraceMessageToGUI = action;
line = new StringBuilder();
}
public override System.Text.Encoding Encoding
{
get { return System.Text.Encoding.Unicode; }
}
public override void Write(char value)
{
if (value == '\r' || value == '\n')
{
counter++;
}
else
{
line.Append(value.ToString());
}
if (counter == 2)
{
WriteTraceMessageToGUI(line.ToString(), Brushes.BlueViolet);
line.Clear();
counter = 0;
}
}
public override void Write(string value)
{
WriteTraceMessageToGUI(value, Brushes.BlueViolet);
}
}

Why is the Hazelcast Near Cache out of sync with the EntryUpdatedListener even though they're in the same process?

I understand that Near Caches are not guaranteed to be synchronized real-time when the value is updated elsewhere on some other node.
However I do expect it to be in sync with the EntryUpdatedListener that is on the same node and therefore the same process - or am I missing something?
Sequence of events:
Cluster of 1 node modifies the same key/value, flipping a value from X to Y and back to X on an interval every X seconds.
A client connects to this cluster node and adds an EntryUpdatedListener to observe the flipping value.
Client receives the EntryUpdatedEvent and prints the value given - as expected, it gives the value recently set.
Client immediately does a map.get for the same key (which should hit the near cache), and it prints a STALE value.
I find this strange - it means that two "channels" within the same client process are showing inconsistent versions of data. I would only expect this between different processes.
Below is my reproducer code:
public class ClusterTest {
private static final int OLD_VALUE = 10000;
private static final int NEW_VALUE = 88888;
private static final int KEY = 5;
private static final int NUMBER_OF_ENTRIES = 10;
public static void main(String[] args) throws Exception {
HazelcastInstance instance = Hazelcast.newHazelcastInstance();
IMap map = instance.getMap("test");
for (int i = 0; i < NUMBER_OF_ENTRIES; i++) {
map.put(i, 0);
}
System.out.println("Size of map = " + map.size());
boolean flag = false;
while(true) {
int value = flag ? OLD_VALUE : NEW_VALUE;
flag = !flag;
map.put(KEY, value);
System.out.println("Set a value of [" + value + "]: ");
Thread.sleep(1000);
}
}
}
public class ClientTest {
public static void main(String[] args) throws InterruptedException {
HazelcastInstance instance = HazelcastClient.newHazelcastClient(new ClientConfig().addNearCacheConfig(new NearCacheConfig("test")));
IMap map = instance.getMap("test");
System.out.println("Size of map = " + map.size());
map.addEntryListener(new MyEntryListener(instance), true);
new CountDownLatch(1).await();
}
static class MyEntryListener
implements EntryAddedListener,
EntryUpdatedListener,
EntryRemovedListener {
private HazelcastInstance instance;
public MyEntryListener(HazelcastInstance instance) {
this.instance = instance;
}
#Override
public void entryAdded(EntryEvent event) {
System.out.println("Entry Added:" + event);
}
#Override
public void entryRemoved(EntryEvent event) {
System.out.println("Entry Removed:" + event);
}
#Override
public void entryUpdated(EntryEvent event) {
Object o = instance.getMap("test").get(event.getKey());
boolean equals = o.equals(event.getValue());
String s = "Event matches what has been fetched = " + equals;
if (!equals) {
s += ", EntryEvent value has delivered: " + (event.getValue()) + ", and an explicit GET has delivered:" + o;
}
System.out.println(s);
}
}
}
The output from the client:
INFO: hz.client_0 [dev] [3.11.1] HazelcastClient 3.11.1 (20181218 - d294f31) is CLIENT_CONNECTED
Jun 20, 2019 4:58:15 PM com.hazelcast.internal.diagnostics.Diagnostics
INFO: hz.client_0 [dev] [3.11.1] Diagnostics disabled. To enable add -Dhazelcast.diagnostics.enabled=true to the JVM arguments.
Size of map = 10
Event matches what has been fetched = true
Event matches what has been fetched = false, EntryEvent value has delivered: 88888, and an explicit GET has delivered:10000
Event matches what has been fetched = true
Event matches what has been fetched = true
Event matches what has been fetched = false, EntryEvent value has delivered: 10000, and an explicit GET has delivered:88888
Near Cache has Eventual Consistency guarantee, while Listeners work in a fire & forget fashion. That's why there are two different mechanisms for both. Also, batching for near cache events reduces the network traffic and keeps the eventing system less busy (this helps when there are too many invalidations or clients), as a tradeoff it may increase the delay of individual invalidations. If you are confident that your system can handle each invalidation event, you can disable batching.
You need to configure the property on member side as events are generated on cluster members and sent to clients.

Javafx: Automatic update of table cell using Thread

I have a Trade class which contains a property currentPrice, which downloads price data from a website using getPricedata() method. The Trade object will show up as a table row in TableView. Now, my task: is to
use the getPricedata() method to grab data from internet, populate the currentPrice cell, whenever the object is created.
relaunch the getPricedata() method to every 1 minute after the object has been created and update table cell.
Below is the basic structure of my code. But I have no idea how to implement this ?
Which package do I need ? Task ? Service ? ScheduledService ?
public class Trade{
private DoubleProperty currentPrice;
// need thread here
public double getPricedata(){
.......
}
}
Use a ScheduledService<Number>, whose Task<Number>'s call() method retrieves and returns the value. Then you can either register an onSucceeded handler with the service, or just bind the Trade's currentPrice to service.lastValue(). Call setPeriod(..) on the service (once) to configure it to run every minute.
Since the currentPrice is being set from the service, you should only expose a ReadOnlyDoubleProperty from your Trade class (otherwise you might try to call currentPriceProperty().set(...) or setCurrentPrice(...), which would fail as it's bound).
I would do something like
public class Trade {
private final ReadOnlyDoubleWrapper currentPrice ;
private final ScheduledService<Number> priceService = new ScheduledService<Number>() {
#Override
public Task<Number> createTask() {
return new Task<Number>() {
#Override
public Number call() {
return getPriceData();
}
};
}
};
public Trade() {
priceService.setPeriod(Duration.minutes(1));
// in case of errors running service:
priceService.setOnFailed(e -> priceService.getException().printStackTrace());
currentPrice = new ReadOnlyDoubleWrapper(0);
currentPrice.bind(priceService.lastValueProperty());
startMonitoring();
}
public final void startMonitoring() {
priceService.restart();
}
public final void stopMonitoring() {
priceService.cancel();
}
public ReadOnlyDoubleProperty currentPriceProperty() {
return currentPrice.getReadOnlyProperty();
}
public final double getCurrentPrice() {
return currentPriceProperty().get();
}
private double getPriceData() {
// do actual retrieval work here...
}
}
(Code just typed in here without testing, but it should give you the idea.)

Adding gauge in location finder class in j2me

I am working on a j2me application which contain a class to find the location of mobile using GPS.I need to include gauge while the location provider API is called and it finds the location.I am new to j2me so still not clear with all the concepts.I am pasting my code below.Please help me through this.Thanks in advance..
package org.ets.utils;
import javax.microedition.lcdui.*;
import javax.microedition.location.*;
import javax.microedition.io.*;
import java.io.*;
import org.ets.midlet.ETS_infozech;
import javax.microedition.midlet.*;
public class Locfinder {
public Locfinder(ETS_infozech midlet)
{
this.midlet = midlet;
}
public static String ex()
{
try {
checkLocation();
} catch (Exception ex)
{
ex.printStackTrace();
}
//System.out.println(string);
return string;
}
public static void checkLocation() throws Exception
{
Location l;
LocationProvider lp;
Coordinates c;
// Set criteria for selecting a location provider:
// accurate to 500 meters horizontally
Criteria cr= new Criteria();
cr.setHorizontalAccuracy(500);
// Get an instance of the provider
lp= LocationProvider.getInstance(cr);
//Request the location, setting a one-minute timeout
l = lp.getLocation(60);
c = l.getQualifiedCoordinates();
if(c != null ) {
// Use coordinate information
double lat = c.getLatitude();
double lon = c.getLongitude();
string = " LAT-" + lat + " LONG-" + lon;
}
}
}
There's no way you can link a Gauge to some task.
You have to set values to the Gauge manually. So you'd create a Gauge and add it to your Form. Then start your code to perform the look-up.
In between your lines of code, you'd add myGauge.setValue(some_value); to increase the indicator.
Of course, this becomes difficult when most of the task is contained in a single line of code, like e.g. lp.getLocation(60);.
I think, in that case, I would create a Thread that automatically increases the value on the Gauge in the 60 seconds, but can be stopped/overridden by a manual setting.
class Autoincrementer implements Runnable {
private boolean running;
private Gauge gauge;
private int seconds;
private int secondsElapsed;
public Autoincrementer(Gauge gauge) {
this.gauge = gauge;
this.seconds = gauge.getMaxValue();
this.running = true;
this.secondsElapsed = 0;
}
public void run() {
if (running) {
secondsElapsed++;
gauge.setValue(secondsElapsed);
if (secondsElapsed>=gauge.getMaxValue()) running = false; // Stop the auto incrementing
try {
Thread.sleep(1000); // Sleep for 1 second
} catch (Exception e) {}
}
}
public void stop() {
running = false;
}
}
You would then create a Gauge and add it to your Form
myGauge = new Gauge("Process", false, 60, 0);
myForm.append(myGauge);
Then start the auto-increment.
myIncrementer = new Autoincrementer(myGauge);
new Thread(myIncrementer).start();
And then call your look-up code.
checkLocation();
Inside your look-up code, add code to stop the auto-incrementing and set the Gauge object to 100%, if the look-up was successful (meaning before the timeout).
myIncrementer.stop();
myGauge.setValue(60);
LWUIT 1.5 can help you in this. Am not sure for Location API which you are using.
But you will get Gauge using LWUIT 1.5. Use Lwuit instead of LCDUI.
http://www.oracle.com/technetwork/java/javame/javamobile/download/lwuit/index.html

Resources