Meter Ingest (SDK sample code)

This sample illustrates ingesting meters in a Spring boot app.

Steps:

  1. Setup Amberflo environment
  2. Setup configuration for service discovery of Amberflo ingestion client
  3. Create helper for mapping object to Amberflo ingestion payload

Maven dependencies (check for latest versions):

<dependencies>
  <dependency>
    <groupId>io.amberflo</groupId>
    <artifactId>metering-java-client</artifactId>
    <version>1.3.6</version>
  </dependency>
  <dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<version>1.18.20</version>
	</dependency>
</dependencies>

Setup the environment to configure Amberflo client settings

  1. Setup the environment to configure the Amberflo SDK client settings
  2. Add following entries to the application.properties file
  3. Setup an environment for service discoverable.
amberflo.apiKey=your-api-key-here
amberflo.region=US_West
amberflo.domain=Prod
amberflo.ingestion.frequency.seconds=1
amberflo.ingestion.batch.size=10
amberflo.isDebug=true
PropertyDescriptionOptions
apiKeyAmberflo API key
regionThe region of where the ingestion client is runningUS_West
domainThe domain can be Prod or DevProd, Dev
ingestion.frequency.secondsFrequency at which queued data will be sent to API.1
ingestion.batch.sizeNumber of messages posted to the API.
amberflo.isDebugLog debug info for ingestion code calling the SDK
import com.amberflo.metering.ingest.meter_message.Domain;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.amberflo.metering.ingest.meter_message.Region;

@Getter
@Component
public class AmberfloEnvironment {

    @Value("${amberflo.apiKey}")
    private String apiKey;

    @Value("${amberflo.region}")
    private Region region;

    @Value("${amberflo.domain}")
    private Domain domain;

    @Value("${amberflo.ingestion.frequency.seconds}")
    private Double ingestionFrequencyInSeconds;

    @Value("${amberflo.ingestion.batch.size}")
    private Integer ingestionBatchSize;
}

Setup Amberflo client bean for service discoverability

  1. Amberflo provides a singleton instance of the Amberflo client to make the ingestion process more efficient. In order to make this client a discoverable service that can be injected as a dependency, create a configuration to return the client instance as a bean.
import com.amberflo.metering.ingest.MeteringContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AmberfloClientConfig {

    @Autowired
    private AmberfloEnvironment amberfloEnvironment;

    @Bean
    public MeteringContext meteringContext() {
        MeteringContext meteringContext = null;
        try{
            meteringContext = MeteringContext.createOrReplaceContext(
                    this.amberfloEnvironment.getApiKey(),
              			//TODO: enter your service name here
              			//The service name will be added for all of your meters as an extra dimension.
                    "service-name",
                    this.amberfloEnvironment.getDomain(),
                    this.amberfloEnvironment.getRegion(),
                    this.amberfloEnvironment.getIngestionFrequencyInSeconds(),
                    this.amberfloEnvironment.getIngestionBatchSize());
            if(meteringContext.meteringInstance() != null) {
                LOGGER.info("Amberflo client initialized with region={}, domain={}, frequency={}, batchSize={}",
                        this.amberfloEnvironment.getRegion(),
                        this.amberfloEnvironment.getDomain(),
                        this.amberfloEnvironment.getIngestionFrequencyInSeconds(),
                        this.amberfloEnvironment.getIngestionBatchSize());
            }
        }
        catch(Exception ex){
            LOGGER.error("Amberflo client initialization failed: {}", ex.getMessage());
            ex.printStackTrace();
        }

        return meteringContext;
    }
}

Entity to Amberflo payload mapper

In this approach the entity is transformed to the ingestion payload using a helper. In this sample, we have an entity called Event which is mapped to the Amberflo SDK ingestion payload in the AmberfloMapper class.

Now AmberfloMapper.ingestMeterForEvent() can be called from anywhere in your code.

Sample entity class:

import java.io.Serializable;
import javax.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "event")
public class Event implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;

    @Column(name = "event_source_type")
    private String eventSourceType;

    @Column(name = "event_type")
    private String eventType;

    @Column(name = "customer_id")
    private String customerId;
}

Sample mapper helper:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;

import static com.amberflo.metering.ingest.MeteringContext.metering;

public class AmberfloMapper {
    private static final Logger LOGGER = LogManager.getLogger();

    public static void ingestMeterForEvent(final Event event, final String meterName){
        try {
            final String customerId = event.getCustomerId();
            final double meterValue = 1.0;
            final LocalDateTime eventTime = LocalDateTime.now(ZoneOffset.UTC);
            final Map<String, String> dimensions = new HashMap();
            dimensions.put("event_source_type", event.getEventSourceType());
            dimensions.put("event_type", event.getEventType());
            metering().meter(customerId, meterName, meterValue, eventTime, dimensions);
            LOGGER.info("Amberflo ingestion: event id {}, customerId {}, meter {}, event source type {}, event type {}",
                    event.getId(), customerId, meterName, dimensions.get("event_source_type"), dimensions.get("event_type"));
        } catch (Exception ex) {
            LOGGER.error("Amberflo ingestion failed: {}", ex.getMessage());
            ex.printStackTrace();
        }
    }
}