SDKs and Recipes
Java SDK- verbosed
1min
1\ meter examples package demo; import com amberflo metering ingest meteringcontext; import com amberflo metering ingest extensions servicemetering; import com amberflo metering ingest meter message domain; import com amberflo metering ingest meter message metermessage; import com amberflo metering ingest meter message metermessagebuilder; import java time localdatetime; import java time zoneid; import java util hashmap; import java util map; import com amberflo metering ingest meter message region; import static com amberflo metering ingest meteringcontext metering; import static com amberflo metering ingest extensions servicemetering servicemetering; import static com amberflo metering ingest extensions customermetering customermetering; / in this app we describe different ways to call the metering services 1 builder 2 factory 3 templates the example itself used the {@link domain#prod} configuration to setup the metering client for more info about each of our api please see the java doc / public class meteringexamples { private final static string meter name = "trancsactioncount"; private final static int meter value = 3; private final static string customer id = "ywjjndu2"; private final static string service call = "process request"; private final static string service name = "magic service"; private final static localdatetime event time = localdatetime now(); private final static double mb used = 15 5; private final static double processing time millis = 100; private final static boolean error flag = true; private final static map\<string, string> extra dimensions map = null; public static void main(string\[] args) throws exception { // step 1 setting up the domain (prod dev) // you need to set the "metering domain" system env var to prod system setproperty(meteringcontext metering domain, domain prod name()); // step 2 send some meters to amberflo sendsomemeters(); // step 3 flush and close the metering client // for efficiency, we send meters to amberflo in batches you can configure the max batch size in // the prod/def metering json file having said that, even if you use a max batch size of 1, you still want // to call this method, especially if use configured 'isasync' to true meteringcontext flushandclose(); // comment 'metering' is autoclosable so instead of step 2 and 3, you can also send meters this way try (final meteringcontext context = meteringcontext getcontext()) { // templates are just and abstraction layer on the top of the metering customermetering() signup(customer id, event time); } } / here we describe the 3 methods to directly send meters 1 builder 2 factory 3 templates / private static void sendsomemeters() { // option 1 create a custom meter with a builder // this option gives you more flexibility regarding the way you construct your meter event, but it // requires more effort on your side, and might be more errors prone than other options // use it only if you need a completely custom meter final metermessage meter = metermessagebuilder createinstance(meter name, event time, customer id) setmetervalue(meter value) build(); metering() meter(meter); // look at this method to see a more advanced example for how to set a meter this way custombuilderadvanced(); // option 2 create a custom message with a factory // a factory is a bit more structured way of creating a meter but less flexible it lets you send // a meter which contains the // a the customer id mandatory (unless you invoke the method within a thread context with // customer info) this is the id of your customer who made a call to your service (let's say) // b the meter name and value required // c the start time optional this can be a start time of a call, or the event time which is relevant // for the meter if the start time is null then the event time will by the current time when sending // the meter // d the extra dimensions map optional this is just a map of string keys to string values containing // important dimensions metering() meter(customer id, meter name, meter value, event time, extra dimensions map); metering() meter(customer id, meter name, meter value, event time, null); // option 3 templates // templates are the most convenient but least flexible option of creating meters explicitly basically // templates are predefined meter types, with a predefined meter name, and predefined meter structure // // why do we need templates ? // let's assume we want to create meters for a service what would we try to measure ? probably we would // want to record commons things such as 'service calls', 'data usage' or 'processing time' now, we don't // want you to reinvent the will for such common use cases, so we created a few domain specific factories that // allows you to create meters more easily // option 3 1 service metering // use the servicemetering to create servicemetering() call(customer id, service call, event time); servicemetering() processingtime(customer id, service call, processing time millis, event time); servicemetering() datausage(customer id, service call, mb used, event time); // see the method below for more advanced\detailed examples of using the meters servicemeteringadvanced(); // option 3 2 customer metering // this templates allow you to create customer (client) related meters customermetering() signup(customer id, event time); customermetering() onboarded(customer id, event time); customermetering() offboarded(customer id, event time); customermetering() login(customer id, event time); // this meter described a case a customer registered to your service, but you rejected the registration // (false data or a malicious customer for example) customermetering() onboardingrejected(customer id, event time); } private static void custombuilderadvanced() { final map\<string, string> sessioninfo = new hashmap<>(); sessioninfo put("session", "789"); final map\<string, string> countryandstateinfo = new hashmap<>(); sessioninfo put("country", "us"); sessioninfo put("state", "wa"); final metermessage meter = metermessagebuilder createinstance(meter name, event time, customer id) // meter value is actually optional param if not set the the meter value will be 1 setmetervalue(meter value) // if you want to capture the end time of the meter event (now), and measure the duration of // it, you can use the this method which will set up the duration as the time diff in millis between // now and the start time calling this method will set the meter type to "millis" captureendtimeandduration() // in our case the duration should be 3 minutes (in millis) // meter type isn't currently in use by amberflo yet if you feel the need to have it // use it we will notice that and adapt our system accordingly setmetertype("millis") // set up service related data // service name is a param to the 'directmeteringclient', nevertheless, you can override it here setservicename(service name) setservicecall(service call) // if you want to mark your meter as error related you can call aserror() / or / aserror(illegalargumentexception class) // you can set up a region setregion(region us west) // the dimensions map gives you the option to add more properties to your meter, which don't // exist as part of the predefined methods of the builder // for example, let's assume you want to add session info to your meter to track a process // or customer request e2e, you can add this dimensions this way setdimensionsmap(sessioninfo) // another example for custom dimensions // let's assume you want to measure customer related events as part of that you want to partition // your customers by country and state so you can add these two as custom attributes setdimensionsmap(countryandstateinfo) // ^^ it's ok call setdimensionsmap multiple times as long as there is no intersection between // the keys of the maps build(); metering() meter(meter); } / the service metering template contains the following {@link servicemetering#call} 1 callcompleted (successfully) 2 callerror 3 call this one is to try and measure a call regardless if it completed successfully or with an error all of these types of calls will produce a {@link servicemetering#call} meter as they indicates the event of finish handling a call (with or without an error) other types of calls there are 3 other more specific type of call which will produce different meter 1 callstarted will produce a {@link servicemetering#call started} meter use this event if you want to have different meters for the start and the end of a call 2 datausage measure data used by the client (in mb) will produce a {@link servicemetering#call data usage} meter 3 processingtime time it took to process a service call request (in millis) will produce a {@link servicemetering#call processing time} meter / private static void servicemeteringadvanced() { // 'call' will produce a meter called "call" and it can be used in many ways servicemetering() call(customer id, service call, event time); servicemetering() call(customer id, service call, error flag, event time); // if you want to mark it as an error servicemetering() call(customer id, service call, error flag, illegalaccesserror class, event time); // error + error type // the service call in the example above isn't the meter name but a dimension // if you find it more convenient you can also record a service call using servicemetering() callcompleted(customer id, service call, event time); // to mark the end of a call that completed successfully servicemetering() callerror(customer id, service call, event time); // to mark the end of a call that completed with an error // we will see soon how these can be used // 'callstarted' as the name suggests, measure an event of start handling a service call regardless of the // results (the call completed successfully or not) servicemetering() callstarted(customer id, service call, event time); // 'processingtime' measures the time it took to process the call in millis servicemetering() processingtime(customer id, service call, processing time millis, event time); // 'datausage' as the name suggests, measures the data returned to the client or used by the call in mb servicemetering() datausage(customer id, service call, mb used, event time); // examples of using multiple of the calls above final runnable methodtorun = () > { try { thread sleep(300); } catch (interruptedexception e) { e printstacktrace(); } }; servicemeteringmulticalls(methodtorun); } / you can have a similar decorator/interceptor method to this one in your code / private static void servicemeteringmulticalls(final runnable runnable) { final localdatetime starttime = localdatetime now(); localdatetime endtime = starttime; try { servicemetering() callstarted(customer id, service call, starttime); runnable run(); endtime = localdatetime now(); servicemetering() callcompleted(customer id, service call, endtime); } catch (final exception e) { endtime = localdatetime now(); servicemetering() callerror(customer id, service call, e getclass(), endtime); } finally { final long durationinmillis = endtime atzone(zoneid systemdefault()) toinstant() toepochmilli() starttime atzone(zoneid systemdefault()) toinstant() toepochmilli(); servicemetering() processingtime(customer id, service call, durationinmillis, endtime); } } }