1 -- Written by Bob Cotton <bob.cotton@gmail.com>
2 -- This is free software; you can redistribute it and/or modify it under
3 -- the terms of the GNU General Public License as published by the Free
4 -- Software Foundation; only version 2 of the License is applicable.
5 drop table metrics cascade;
6 drop table hostname_dimension cascade;
7 drop table plugin_dimension cascade;
8 drop table type_dimension cascade;
9 drop type datasource_type cascade;
11 create type datasource_type as ENUM ('GUAGE', 'COUNTER');
13 create table metrics (id serial primary key,
15 measure double precision default 0,
16 hostname_id integer not null,
17 plugin_id integer not null,
18 type_id integer not null
21 create table hostname_dimension (id serial primary key,
22 hostname varchar(64) not null);
24 create table plugin_dimension (id serial primary key,
25 plugin varchar(64) not null,
26 plugin_instance varchar(64));
28 create table type_dimension (id serial primary key,
29 ds_type datasource_type,
30 type varchar(64) not null,
31 type_name varchar(64) not null,
32 type_instance varchar(64));
34 create or replace function insert_metric(in_timestamp timestamp,
35 in_measure double precision,
37 in_ds_type datasource_type,
39 in_plugin_instance text,
42 in_type_instance text) returns void as $$
48 select into host_id id from hostname_dimension where hostname = in_hostname;
50 insert into hostname_dimension (hostname) values (in_hostname) returning id into host_id;
53 IF in_plugin_instance IS NULL THEN
54 select into a_plugin_id id from plugin_dimension where plugin = in_plugin and plugin_instance is null;
56 select into a_plugin_id id from plugin_dimension where plugin = in_plugin and plugin_instance = in_plugin_instance;
60 insert into plugin_dimension (plugin, plugin_instance) values (in_plugin, in_plugin_instance) returning id into a_plugin_id;
63 IF in_type_instance IS NULL THEN
64 select into a_type_id id from type_dimension where type = in_type and type_name = in_type_name and type_instance is null;
66 select into a_type_id id from type_dimension where type = in_type and type_name = in_type_name and type_instance = in_type_instance;
70 insert into type_dimension (type, ds_type, type_name, type_instance) values (in_type, in_ds_type, in_type_name, in_type_instance) returning id into a_type_id;
73 insert into metrics (timestamp, measure, hostname_id, plugin_id, type_id) values (in_timestamp, in_measure, host_id, a_plugin_id, a_type_id);
77 create or replace function get_interval(start_timestamp timestamp, length interval, step text) returns SETOF timestamp as $$
79 v_timestamp timestamp;
80 end_timestamp timestamp;
82 v_timestamp := start_timestamp;
83 end_timestamp := start_timestamp + length;
84 WHILE v_timestamp <= end_timestamp LOOP
85 RETURN NEXT v_timestamp;
86 v_timestamp := v_timestamp + ('1' || step)::interval;
91 create or replace function create_partition_trigger(parent text,
92 start_timestamp timestamp,
95 format text) returns void as $trigger$
103 v_current_date := date(start_timestamp);
104 v_function := 'CREATE OR REPLACE FUNCTION ' || parent || '_insert_trigger() '
105 || 'RETURNS TRIGGER LANGUAGE plpgsql AS $$ '
108 FOR v_start_date in select * from get_interval(start_timestamp, length, step) LOOP
109 select trim(to_char(v_start_date, format)) into v_suffix;
110 IF v_current_date = v_start_date THEN
113 v_body := ' ELSEIF ';
115 v_body := v_body || ' NEW.timestamp >= ''' || v_start_date || '''::timestamp and '
116 || ' NEW.timestamp < ''' || v_start_date + ( '1' || step)::interval || '''::timestamp THEN '
117 || ' INSERT INTO ' || parent || '_' || v_suffix
118 || ' values (NEW.*); ';
119 v_function := v_function || v_body;
121 v_function := v_function || 'ELSE RETURN NEW; END IF; RETURN NULL; END; $$';
124 $trigger$ LANGUAGE plpgsql;
126 create or replace function create_partition_tables(parent text, start_timestamp timestamp, length interval, step text, format text) returns void as $$
133 FOR v_start_date in select * from get_interval(start_timestamp, length, step) LOOP
134 select trim(to_char(v_start_date, format)) into v_suffix;
135 select parent || '_' || v_suffix into table_name;
136 select 'create table ' || table_name
137 || ' (CHECK (timestamp >= ' || quote_literal(v_start_date)
138 || '::timestamp and timestamp < ' || quote_literal(v_start_date + ( '1' || step)::interval)
139 || '::timestamp)) INHERITS (' || parent || ');'
142 EXECUTE 'create index index_' || table_name || '_on_timestamp_hostname_and_plugin_and_type on ' || table_name || ' (timestamp, hostname_id, plugin_id, type_id);';
147 -- if you are using postgres 8.4, which introduced window functions
148 -- you can use something like this to to create a view on rows that come from
149 -- COUNTER plugins. Because the real measurement is the difference of
150 -- the last sample to the next sample, use the lag() function to do that math.
151 -- This will create a combined view of both COUNTER and GUAGE types.
153 -- WARNING - for large datasets THIS WILL BE SLOW!
155 -- create view metrics_view as
157 -- ((m.measure - lag(m.measure)
158 -- over(partition by m.hostname_id,
160 -- p.plugin_instance,
163 -- order by timestamp, m.hostname_id, p.plugin, p.plugin_instance, t.type, t.type_instance))) AS metric,
167 -- FROM metrics m, plugin_dimension p, type_dimension t
168 -- where m.type_id = t.id
169 -- and m.plugin_id = p.id
170 -- and t.ds_type = 'COUNTER'
172 -- select timestamp, m.measure as metric,
176 -- FROM metrics m, type_dimension t
177 -- where m.type_id = t.id
178 -- and t.ds_type = 'GUAGE';