Getting Started
Amberflo SDKs

Java

9min
easily integrates with tomcat/spring github repo with java sdk samples https //github com/amberflo/metering java sample https //github com/amberflo/metering java sample simple main class example https //github com/amberflo/metering java sample/blob/main/metering sample/src/main/java/demo/ingest/meteringexamples java https //github com/amberflo/metering java sample/blob/main/metering sample/src/main/java/demo/ingest/meteringexamples java maven https //mvnrepository com/artifact/io amberflo/metering java client https //mvnrepository com/artifact/io amberflo/metering java client \<! https //mvnrepository com/artifact/io amberflo/metering java client > \<dependency> \<groupid>io amberflo\</groupid> \<artifactid>metering java client\</artifactid> \</dependency> batching records amberflo io libraries are built to support high throughput environments that means you can safely send hundreds of meter records per second for example, you can chose to deploy it on a web server that is serving hundreds of requests per second however, every call does not result in a http request, but is queued in memory instead messages are batched and flushed in the background, allowing for much faster operation the size of batch and rate of flush can be customized defaults the library will flush every 100 messages (configuration parameter maxbatchsize) or if 0 5 seconds has passed since the last flush (configuration parameter maxdelayinsec) what happens if there are just too many messages? if the module detects that it can’t flush faster than it’s receiving messages, it’ll simply stop accepting messages this allows your program to continually run without ever crashing due to a backed up metering queue the maximum meters kept in memory is 100,000 (configuration parameter maxasyncqueyesize) flush on demand (blocking call) you can flush on demand for example, at the end of your program, you’ll want to flush to make sure there’s nothing left in the queue just call the flush method meteringcontext flushandclose(); please note calling this method will block the calling thread until there are no messages left in the queue you’ll want to use it as part of your cleanup scripts and avoid using it as part of the request lifecycle using s3 you can use the java sdk to write to s3, and amberflo will read it from there 1\ create a metering client from configuration file / full sample at https //github com/amberflo/metering java sample/blob/main/metering sample/src/main/java/demo/ingest/s3meteringexamples java / import com amberflo metering ingest meteringcontext; import com amberflo metering ingest meter message metermessage; import com amberflo metering ingest meter message metermessagebuilder; import java time localdatetime; import static com amberflo metering ingest meteringcontext metering; / in this app we describe different ways to call the s3metering services 1 builder 2 factory for more info about each of our api please see the java doc / public class s3meteringexamples { private final static string meter name = "trancsactioncount"; private final static int meter value = 2210; private final static string customer id = "batman"; private final static localdatetime event time = localdatetime now(); private final static string s3 metering config file = "s3 metering json"; private final static string access key = "accesskey"; private final static string secret key = "secretkey"; private final static string bucket name = "bucketname"; public static void main(string\[] args) { creates3meteringclientwithcredentials(); } / a way to to create s3metering client using the config file by specifying the clienttype, bucketname, httpretriescount, httptimeoutseconds, isasync parameters in the json file" / private static void creates3meteringclientwithfile() throws exception { try(meteringcontext context = meteringcontext contextwiths3clientfromfile(s3 metering config file)) { final metermessage meter = metermessagebuilder createinstance(meter name, event time, customer id) setmetervalue(meter value) build(); metering() meter(meter); } } / a way to to create s3metering client using the bucket name, access key, secret key, retries, timeout to the context / private static void creates3meteringclientwithcredentials() { try(meteringcontext context = meteringcontext contextwiths3client(bucket name, access key, secret key, 5, 30)) { final metermessage meter = metermessagebuilder createinstance(meter name, event time, customer id) setmetervalue(meter value) build(); metering() meter(meter); } } } 2\ create a s3 metering client with with credentials from code / full sample at https //github com/amberflo/metering java sample/blob/main/metering sample/src/main/java/demo/ingest/s3meteringexamples java / import com amberflo metering ingest meteringcontext; import com amberflo metering ingest meter message metermessage; import com amberflo metering ingest meter message metermessagebuilder; import java time localdatetime; import static com amberflo metering ingest meteringcontext metering; / in this app we describe different ways to call the s3metering services 1 builder 2 factory for more info about each of our api please see the java doc / public class s3meteringexamples { private final static string meter name = "trancsactioncount"; private final static int meter value = 2210; private final static string customer id = "batman"; private final static localdatetime event time = localdatetime now(); private final static string s3 metering config file = "s3 metering json"; private final static string access key = "accesskey"; private final static string secret key = "secretkey"; private final static string bucket name = "bucketname"; public static void main(string\[] args) { creates3meteringclientwithcredentials(); } / a way to to create s3metering client using the config file by specifying the clienttype, bucketname, httpretriescount, httptimeoutseconds, isasync parameters in the json file" / private static void creates3meteringclientwithfile() throws exception { try(meteringcontext context = meteringcontext contextwiths3clientfromfile(s3 metering config file)) { final metermessage meter = metermessagebuilder createinstance(meter name, event time, customer id) setmetervalue(meter value) build(); metering() meter(meter); } } / a way to to create s3metering client using the bucket name, access key, secret key, retries, timeout to the context / private static void creates3meteringclientwithcredentials() { try(meteringcontext context = meteringcontext contextwiths3client(bucket name, access key, secret key, 5, 30)) { final metermessage meter = metermessagebuilder createinstance(meter name, event time, customer id) setmetervalue(meter value) build(); metering() meter(meter); } } } code examples simple ingest meter final double metervalue = 2d; final localdatetime accuratemetertime = localdatetime now(zoneoffset utc); final map\<string, string> dimensions = new hashmap<>(); system setproperty(meteringcontext metering domain, domain prod name()); // use the app key for authentication //meteringcontext context = meteringcontext createorreplacecontext("appkey") meteringcontext createorreplacecontext("appkey", "myapp", domain prod,region us west, 1, 10); // simple meter call this call is non blocking and batched for performance context meteringinstance() meter("customerid", "metername",metervalue,accuratemetertime,dimensions); ingest examples https //github com/amberflo/metering java sample/tree/main/metering sample/src/main/java/demo/ingest https //github com/amberflo/metering java sample/tree/main/metering sample/src/main/java/demo/ingest 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(zoneoffset utc); 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(zoneoffset utc); localdatetime endtime = starttime; try { servicemetering() callstarted(customer id, service call, starttime); runnable run(); endtime = localdatetime now(zoneoffset utc); servicemetering() callcompleted(customer id, service call, endtime); } catch (final exception e) { endtime = localdatetime now(zoneoffset utc); 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); } } } usage example https //github com/amberflo/metering java sample/blob/main/metering sample/src/main/java/demo/usage/usageexample java https //github com/amberflo/metering java sample/blob/main/metering sample/src/main/java/demo/usage/usageexample java package demo usage; import com amberflo metering usage clients usageclient; import com amberflo metering usage model request ; import com amberflo metering usage model response detailedmeteraggregation; import java time offsetdatetime; import java util list; import java util map; / an example app to show the main use cases and rules of the 'usage api' / public class usageexample { private static final boolean ascending = true; public static final string customer id field = "customerid"; public static void main(final string\[] args) { // step 1 create the client final string appkey = system getproperty("amberflo app key"); final usageclient usageclient = new usageclient(appkey); // step 2 query the system // if you want simple statistics for all of the official meters in your account use the 'all' api querytheallapi(usageclient); // if you want to create a custom query for any specific meter use the "get" api querythegetapi(usageclient); // for a batch of custom queries use the "batch" api querythegetbatchapi(usageclient); } private static void querytheallapi(final usageclient usageclient) { // creating a simple 'all' api request can be pretty simple // 1 use one of the timerangefactory methods to easily create a time range for your query // 2 use the allmetersaggregationsrequestbuilder to create a request // 3 provide the all request to the usage client and get the results final timerange timerange1 = timerangefactory yeartodate(); final allmetersaggregationsrequest request1 = allmetersaggregationsrequestbuilder instance(timerange1) build(); // each item in the list corresponds to an official 'meter' defined by you in advance final list\<detailedmeteraggregation> meteraggregations1 = usageclient getall(request1); system out println(meteraggregations1); // you can also look at x days backwards (for example) // the start time of the result will be (now x days) truncated to the beginning of the day // for example if now is 3/27/2021 02 53 and x = 4 then the result of calling this method is 3/23/2021 00 00 final timerange timerange2 = timerangefactory truncatedlastdays(4); final allmetersaggregationsrequest request2 = allmetersaggregationsrequestbuilder instance(timerange2) build(); final list\<detailedmeteraggregation> meteraggregations2 = usageclient getall(request2); // you can also look at x month backwards (for example) // the start time of the result will be (now x days) truncated to the beginning of the month // for example if now is 3/27/2021 02 53 and x = 2 then the result of calling this method is 1/1/2021 00 00 final timerange timerange3 = timerangefactory truncatedlastmonths(2); final allmetersaggregationsrequest request3 = allmetersaggregationsrequestbuilder instance(timerange3) build(); final list\<detailedmeteraggregation> meteraggregations3 = usageclient getall(request3); // truncatedlastweeks and truncatedlasthours have similar truncation logic // the reason we truncate is related to the way the usage api works let's look at the example below and then // explain the reason final timerange timerange4 = timerangefactory truncatedlastdays(4); final allmetersaggregationsrequest request4 = allmetersaggregationsrequestbuilder instance(timerange4) settimegroupinginterval(aggregationinterval day) build(); final list\<detailedmeteraggregation> meteraggregations4 = usageclient getall(request4); // as you can see in the example above we asked for the results with a timegroupinginterval of a day // asking this will cause the usage api to provide you with statistics for each day of the time range you // asked for for example, if you asked for the time range {3/23/2021 05 00 today}, then for each meter you // will get a statistic for the entire time range as well as a statistic for each day starting from hour 00 00 // so basically the usage api will provide you with statistics for the time range of {3/23/2021 05 00 today} // to make it less confusing, we provide you with "truncated" methods which already produce the truncated // hour/day/week/month on the client side // the truncated methods can also help you getting the beginning of the week (let's say) final timerange timerange5 = timerangefactory truncatedlastweeks(0); final allmetersaggregationsrequest request5 = allmetersaggregationsrequestbuilder instance(timerange5) settimegroupinginterval(aggregationinterval day) build(); final list\<detailedmeteraggregation> meteraggregations5 = usageclient getall(request5); // using the all api you can ask to filter the meters for a certain customer id final timerange timerange6 = timerangefactory truncatedlastweeks(0); final allmetersaggregationsrequest request6 = allmetersaggregationsrequestbuilder instance(timerange6) setfilterbycustomerid("customer id 123") settimegroupinginterval(aggregationinterval day) build(); final list\<detailedmeteraggregation> meteraggregations6 = usageclient getall(request6); // last, regarding the time range we will mention that you can define a custom time range for your query // just notice that the usage api extends the time range you provide according to the provided // aggregationinterval (or to aggregationinterval hour if no aggregationinterval was provided) // so for example a query with a time of {3/23/2021 05 21 3/29/2021 08 21} and a aggregationinterval day // will be treated as {3/23/2021 00 00 3/30/2021 00 00} and a aggregationinterval day final timerange timerange = timerange builder() starttimeinseconds(offsetdatetime now() minusmonths(2) toepochsecond()) endtimeinseconds(offsetdatetime now() minusmonths(1) toepochsecond()) build(); final allmetersaggregationsrequest request = allmetersaggregationsrequestbuilder instance(timerange) settimegroupinginterval(aggregationinterval day) build(); final list\<detailedmeteraggregation> meteraggregations = usageclient getall(request); } private static void querythegetapi(final usageclient usageclient) { // querying the get api is the custom and more advanced way of querying the usage api // at the very least you need to provide the meter name, aggregation type, and time range final string meterapiname = "mymeter"; final timerange timerange = timerangefactory yeartodate(); final meteraggregationmetadata request1 = meteraggregationmetadatabuilder instance(meterapiname, aggregationtype sum, timerange) build(); final detailedmeteraggregation result1 = usageclient get(request1); system out println(result1); // you can use all available meter types, just be aware that (currently) amberflo has indexes only // for the official 'aggregationtype' of your meter so querying for a different type might // cause the query to be slower final meteraggregationmetadata request2 = meteraggregationmetadatabuilder instance(meterapiname, aggregationtype min, timerange) build(); final detailedmeteraggregation result2 = usageclient get(request2); // you can ask to partition the results by a certain field(s) when doing this amberflo will provide // you with statistics per group final meteraggregationmetadata request3 = meteraggregationmetadatabuilder instance(meterapiname, aggregationtype sum, timerange) setgroupby(list of(customer id field)) build(); final detailedmeteraggregation result3 = usageclient get(request3); // partitioning can yield a lot of results, and there is a size limit of 6mb for the entire serialized // detailedmeteraggregation response so you better add a 'take' clause when partitioning // the query below will provide you with statistics for the top 5 customers with the highest meter sum for the // time range you provided final meteraggregationmetadata request4 = meteraggregationmetadatabuilder instance(meterapiname, aggregationtype sum, timerange) setgroupby(list of(customer id field)) settake(new take(5, !ascending)) build(); final detailedmeteraggregation result4 = usageclient get(request4); // as with the 'all' api you can also ask to partition each group of statistics by units of time // in the example below we the usage api will return you statistics for the top 5 customer, where for each // customer you will get statistics for the entire time range, as well as for each day // just notice that the usage api extends the time range you provide according to the provided // aggregationinterval (or to aggregationinterval hour if no aggregationinterval was provided) // so for example a query with a time of {3/23/2021 05 21 3/29/2021 08 21} and a aggregationinterval day // will be treated as {3/23/2021 00 00 3/30/2021 00 00} and a aggregationinterval day final meteraggregationmetadata request5 = meteraggregationmetadatabuilder instance(meterapiname, aggregationtype sum, timerange) settimegroupinginterval(aggregationinterval day) setgroupby(list of(customer id field)) settake(new take(5, !ascending)) build(); final detailedmeteraggregation result5 = usageclient get(request5); // last we will mention that you can define filters for your query // the example below yields statistics for the top 5 "premium" or "gold" customers in the us // assuming you have this fields if you don't the usage api will throw an exception try { final meteraggregationmetadata request6 = meteraggregationmetadatabuilder instance(meterapiname, aggregationtype sum, timerange) settimegroupinginterval(aggregationinterval day) setgroupby(list of(customer id field)) setfilter(map of("customertier", list of("premium", "gold"), "country", list of("us"))) settake(new take(5, !ascending)) build(); final detailedmeteraggregation result6 = usageclient get(request6); } catch (final runtimeexception exception) { system out println(exception); } } private static void querythegetbatchapi(final usageclient usageclient) { // the "batch" api is exactly the same as the "get" api only the you provide it with a batch // of request and it return you a batch of results final string meterapiname1 = "mymeter1"; final string meterapiname2= "mymeter2"; final timerange timerange = timerangefactory yeartodate(); final meteraggregationmetadata request1 = meteraggregationmetadatabuilder instance(meterapiname1, aggregationtype sum, timerange) build(); final meteraggregationmetadata request2 = meteraggregationmetadatabuilder instance(meterapiname2, aggregationtype sum, timerange) build(); final list\<detailedmeteraggregation> result1 = usageclient getbatch(list of(request1, request2)); system out println(result1); } create a customer https //github com/amberflo/metering java sample/blob/main/metering sample/src/main/java/demo/customer details/customerdetailsexample java https //github com/amberflo/metering java sample/blob/main/metering sample/src/main/java/demo/customer details/customerdetailsexample java package demo customer details; import com amberflo metering customer details clients customerdetailsclient; import com amberflo metering customer details model customerdetails; import java util map; import java util uuid; / an example app which shows how to interact with the customer details api / public class customerdetailsexample { public static void main(final string\[] args) { // create the client final string appkey = system getproperty("amberflo app key"); final customerdetailsclient client = new customerdetailsclient(appkey); // create a customer is simple just define a customer // id must be unique and this will be the id that you use when ingesting a meter for the customer or // querying the usage api final string customerid = uuid randomuuid() tostring(); // name is mandatory but not necessarily unique final string customername = "moishe oofnik"; // https //www google com/search?q=moishe+oofnik // traits are optional and suppose to capture additional data about the user final map\<string, string> traits = map of("tv show", "rechov sumsum"); // https //www google com/search?q=rechov+sumsum final customerdetails customerdetails = new customerdetails(customerid, customername, traits); client add(customerdetails); // you shouldn't be able to add the same client again try { client add(customerdetails); } catch (final runtimeexception exception) { system out println(exception); } // but you can update it final string customername2 = "kippi ben kippod"; // https //www google com/search?q=kippi+ben+kippod final customerdetails updatedcustomer = new customerdetails(customerid, customername2, traits); client update(updatedcustomer); // if you aren't sure if the customer exists you can query the system or just call client addorupdate(customerdetails); // as mentioned you can always query the system for a given customer id final customerdetails customerdetailsresult = client get(customerid); system out println("retrieved customer "); system out println(customerdetailsresult); } } configuration example { "clienttype" "directclient", "maxasyncqueyesize" 20000, "isasync" true, "params" { "maxdelayinsec" 0 5, "apikey" "y2hhbmdlbwu=", "accountname" "myaccount", "maxbatchsize" 100, "servicename" "myservicename" } }