Wednesday, December 9, 2015

Using Prometheus with Java in a Jersey project

Step 1, add the dependency to your project. If you're using maven, add the dependency:

<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>simpleclient_servlet</artifactId>
    <version>0.0.6</version>
</dependency>

Step 2, create a class and register some metrics. Here I have a summary and some counters:

public class Metrics {

    public static final Summary requestLatency = Summary.build()
            .name("requests_latency_seconds")
            .help("Request latency in seconds.").register();

    public static final Counter requestFailures = Counter.build()
            .name("requests_failures_total")
            .help("Request failures.").register();

    public static final Counter requestsTotal = Counter.build()
            .name("requests_total")
            .help("Request.").register();

    public static final Counter uploadedFilesSucceeded = Counter.build()
            .name("upload_file_success")
            .help("Total files uploaded to S3.").register();

    public static final Counter tmpFilesNotCleared = Counter.build()
            .name("temp_files_not_cleared")
            .help("Total files that could not be removed from cache").register();

}

Step 3, set a class level variable in your main class to instantiate your Metrics class:

private final Metrics metrics = new Metrics();


Step 4, manipulate your metrics in your code as needed. For example you need to call the inc() function on your counters to increment them. You can add to the requestLatency metric as follows:

@GET
@Path("/something")
@Produces(MediaType.TEXT_PLAIN)
public String Something() {
    try {
        Summary.Timer timer = Metrics.requestLatency.startTimer();
        // do some work ...
        timer.observeDuration();
    } catch (Exception e) {
        return e.getMessage();
    }
    return "It works!";
}


Step 5, add a web method to dish out your metrics. This is the part that I did not like from other online examples (e.g. http://www.boxever.com/easy-java-instrumentation-with-prometheus) ... since they use the Metrics Servlet provided by Prometheus and all that does is user the writer to gather the data for you, so you need to mess with registering and deploying a new servlet within your code. TOO MUCH HASSLE. Just do what the Prometheus servlet does. Load the registry and use the TextFormat class to get your metrics. No need to deploy a servlet! :

@GET
@Path("/metrics")
@Produces(MediaType.TEXT_PLAIN)
public String Metrics() {
    StringWriter writer = new StringWriter();
    try {
        io.prometheus.client.exporter.common.TextFormat.write004(
                writer, CollectorRegistry.defaultRegistry.metricFamilySamples());
    } catch (Exception e) {
        return e.getMessage();
    }
    return writer.toString();
}

Done!


Here is some sample output from one of our apps using this technique:

# HELP requests_failures_total Request failures.
# TYPE requests_failures_total counter
requests_failures_total 0.0
# HELP temp_files_not_cleared Total files that could not be removed from cache
# TYPE temp_files_not_cleared counter
temp_files_not_cleared 0.0
# HELP requests_latency_seconds Request latency in seconds.
# TYPE requests_latency_seconds summary
requests_latency_seconds_count 0.25
requests_latency_seconds_sum 1.0
# HELP upload_file_success Total file uploaded to S3.
# TYPE upload_file_success counter
upload_file_success 25874588.0
# HELP requests_failures_total Request failures.
# TYPE requests_failures_total counter
requests_failures_total 2.0

Wednesday, November 25, 2015

Postgresql upsert example with CTE (before upsert support from 9.5)


 with heartbeat_data (source, time) as (  
  values ('test', now())  
 ),  
 update_query as (  
  update dvs_system.heartbeats  
    set last_beat = heartbeat_data.time  
  from heartbeat_data  
  where source_key = heartbeat_data.source  
  returning true as updated  
 )   
 insert into dvs_system.heartbeats (source_key, last_beat)  
  select source, time  
  from heartbeat_data  
  where not exists (  
   select 1 from update_query where updated = TRUE  
  )  
 ;  


Reference: http://stackoverflow.com/questions/1109061/insert-on-duplicate-update-in-postgresql/8702291#8702291

Monday, October 5, 2015

Postgres: Create a function to create a new logging table which inherits from another

When creating large logging tables, it better to define the structure of the logging table then create tables that inherit from that table, to put the data into. It makes look-ups on the table faster if you are searching for info in your logs relevant to data in one partitioned child table and it also makes it easier to trim the logs since you can just drop a child table of logs when the time is appropriate.

See http://www.postgresql.org/docs/9.1/static/ddl-partitioning.html

 
 
 CREATE OR REPLACE FUNCTION app_system.create_request_log_partition(_date timestamp without time zone)  
  RETURNS void AS  
  $BODY$  
 DECLARE  
      _table text := format('request_log_%s_q%s', date_part('year', _date), date_part('quarter', _date));  
 BEGIN  
        
      EXECUTE  
            'CREATE TABLE system.'|| _table ||'() INHERITS (system.access_log);'||E'\n'  
           ||'CREATE INDEX '|| _table ||'_created_idx ON system.'|| _table ||'(created_at);'||E'\n'  
           ||'CREATE INDEX '|| _table ||'_api_request_idx ON system.'|| _table ||'(api_request);'||E'\n'  
           ||'GRANT INSERT, SELECT ON system.'|| _table ||' TO myapp;'||E'\n'  
           ;  
 END;  
 $BODY$  
 LANGUAGE plpgsql VOLATILE  
 COST 100;  
 ALTER FUNCTION app_system.create_request_log_partition(timestamp without time zone) OWNER TO postgres;  
   

Tuesday, September 8, 2015

Generating self-signed SSL cert and PEM

Sign in as root then run this

cd /etc/ssl
openssl req -x509 -new -nodes -newkey rsa:2048 -keyout haproxy.key -out haproxy.crt
cat ./haproxy.crt ./haproxy.key > ./haproxy.pem

You can  name the files whatever you want instead of using "haproxy", which I use since I like to have SSL termination in my haproxy server.

Wednesday, September 2, 2015

Injection GIT branch / tag name into config.properties file

Prerequisite: In your project you need the file src/main/resources/config.properties

Of course you can adapt to using whatever file you want.

Note that this assumes you're using a "version=" property in your config.properties file


Step 1: Add the maven plugin to run an executable

1:  #!/usr/bin/env bash  
2:    
3:  # Get the git branch / tag name  
4:    
5:  # first, see of we have branch information (this will not be available if we checked out a tag)  
6:  TAG_OR_BRANCH="$(git rev-parse --abbrev-ref HEAD | egrep -o '([0-9]{1,}\.)+[0-9]{1,}')"  
7:    
8:  if [ "$TAG_OR_BRANCH" == "" ]; then  
9:    
10:    # if we can't get branch info, then we must be in a tag, so use that  
11:    TAG_OR_BRANCH="$(git describe | egrep -o '([0-9]{1,}\.)+[0-9]{1,}+(-b[0-9]{1,})')"  
12:  fi  
13:    
14:  # Remove the version from the properties file  
15:  sed -i '/^version=/ d' src/main/resources/static/version  
16:    
17:  # Add the version to the properties file  
18:  echo "Writing version $TAG_OR_BRANCH"  
19:  echo "version=$TAG_OR_BRANCH" >> src/main/resources/static/version  

Monday, August 3, 2015

Generate Golang struct (model) from Postgres tables

A handy Postgres SQL statement to generate Golang models (structs) for you.


WITH models AS (
  WITH data AS (
    SELECT
        replace(initcap(table_name::text), '_', '') table_name,
        replace(initcap(column_name::text), '_', '') column_name,
        CASE data_type
        WHEN 'timestamp without time zone' THEN 'time.Time'
        WHEN 'timestamp with time zone' THEN 'time.Time'
        WHEN 'boolean' THEN 'bool'
        -- add your own type converters as needed or it will default to 'string'
        ELSE 'string'
        END AS type_info,
        '`json:"' || column_name ||'"`' AS annotation    
    FROM information_schema.columns
    WHERE table_schema IN ('dvs_app', 'dvs_system')
    ORDER BY table_schema, table_name, ordinal_position
  )
    SELECT table_name, STRING_AGG(E'\t' || column_name || E'\t' || type_info || E'\t' || annotation, E'\n') fields
    FROM data
    GROUP BY table_name
)
SELECT 'type ' || table_name || E' struct {\n' || fields || E'\n}' models
FROM models ORDER BY 1

Tuesday, June 30, 2015

Handy PowerShell Scripts

(because I don't want to add another GitHub repo)


Invert mouse scrolling (from http://superuser.com/questions/310681/inverting-direction-of-mouse-scroll-wheel)

Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Enum\HID\*\*\Device` Parameters FlipFlopWheel -EA 0 | ForEach-Object { Set-ItemProperty $_.PSPath FlipFlopWheel 1 }