forked from lozzd/cdn_scripts
/
fastly_to_graphite.php
executable file
·158 lines (130 loc) · 5.34 KB
/
fastly_to_graphite.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/bin/env php
<?php
# Takes the stats from the Fastly reporting API and feeds them into Graphite.
# Your Fastly API key
const FASTLY_KEY = "";
# Configure your Fastly services goes here:
# - The array key is the name of the service and the graphite key that will be used
# - The array value is the service ID, which can be pulled from the Fastly UI.
$config = array('www' => 'AbCdEfGhIjKlMnOpQrStUv', 'img' => 'a1bc3d4e5f6g7h8i9j0k1l');
const GRAPHITE_HOST = 'graphite.yourcompany.com';
const GRAPHITE_PORT = '2003';
const GRAPHITE_PREFIX = 'cdn.fastly';
# Can adjust these if you wish. The intentional delay in reporting is a safeguard in case
# the API doesn't have complete stats yet. Feel free to experiment.
const STATS_PERIOD = "minutely";
const STATS_START = "10 minutes ago";
const STATS_END = "9 minutes ago";
const FASTLY_API_URL = "https://api.fastly.com";
# End configuration
function getStatsJSON($service_id) {
// Get the JSON API data from Fastly and return it.
$start = new DateTime(STATS_START, new DateTimeZone('UTC'));
$end = new DateTime(STATS_END, new DateTimeZone('UTC'));
$opts = array(
'http' => array('method' => 'GET',
'header' => "X-Fastly-Key: " . FASTLY_KEY . "\r\n"
)
);
$context = stream_context_create($opts);
$url = FASTLY_API_URL . "/service/" . $service_id . "/stats/summary?start_time=" . $start->format('U') . "&end_time=" . $end->format('U');
echo date("r") . " - Getting data from Fastly API from $url\n";
$content = file_get_contents($url, false, $context);
$json = json_decode($content, true);
return $json['stats'];
}
function runStats($service_id, $service_name) {
if (!$this_stats = getStatsJSON($service_id)) {
echo date("r") . " - Pulling stats failed, please check error messages! Probably failed auth or service ID wrong.\n";
return;
}
echo date("r") . " - Processing Data\n";
$start = new DateTime(STATS_START, new DateTimeZone('UTC'));
$end = new DateTime(STATS_END, new DateTimeZone('UTC'));
$duration = $end->format('U') - $start->format('U');
// Now perform post processing for various metrics.
foreach ($this_stats as $dc_name => $dc_stats) {
foreach ($dc_stats as $stat_name => $stat_value) {
switch ($stat_name) {
// All of these need just dividing by the interval ($duration)
case "requests":
case "uncacheable":
case "pass":
case "status_1xx":
case "status_2xx":
case "status_3xx":
case "status_4xx":
case "status_5xx":
case "hits":
case "pipe":
case "miss":
case "status_204":
case "status_200":
case "status_503":
case "status_302":
case "status_304":
case "status_301":
$this_stats[$dc_name][$stat_name] = makePerSecond($this_stats[$dc_name][$stat_name], $duration);
break;
// All of the below are measured in bytes and across all requests, so convert to bits, and per second.
// Don't divide by requests unless you want average size of request!
case "header_size":
case "body_size":
$this_stats[$dc_name][$stat_name] = bytesToBits($this_stats[$dc_name][$stat_name]);
$this_stats[$dc_name][$stat_name] = makePerSecond($this_stats[$dc_name][$stat_name], $duration);
break;
default:
unset($this_stats[$dc_name][$stat_name]);
}
}
}
// Calculations done... Send to graphite.
$timestamp = $end->format('U');
parseStatsToGraphite($this_stats, $service_name, $timestamp);
}
function parseStatsToGraphite(Array $stats, $graphite_prefix, $timestamp) {
// Flatten the array and send everything to the graphite server
$graphite_stats_flat = array_flat($stats);
foreach ($graphite_stats_flat as $k => $v) {
$graphite_key = GRAPHITE_PREFIX . ".{$graphite_prefix}.{$k}";
sendToGraphite($timestamp, $graphite_key, $v);
}
}
function sendToGraphite($timestamp, $key, $value) {
// Connect to graphite and send the data
$data = "$key $value $timestamp";
echo "Sending to graphite: $data\n";
$fh = fsockopen(GRAPHITE_HOST, GRAPHITE_PORT);
if ($fh) {
fwrite($fh, "$data\r\n");
fclose($fh);
} else {
echo "Could not open connection to graphite!\n";
}
}
function makePerSecond($value, $minute_period) {
return $value / $minute_period;
}
function bytesToBits($value) {
return $value * 8;
}
function array_flat($array, $prefix = '')
{ // Handy function that turns a multidimensional array into a flat key with a prefix (e.g. a full stop for graphite)
$result = array();
foreach ($array as $key => $value) {
$new_key = $prefix . (empty($prefix) ? '' : '.') . $key;
if (is_array($value)) {
$result = array_merge($result, array_flat($value, $new_key));
} else {
$result[$new_key] = $value;
}
}
return $result;
}
echo date("r") . " - Beginning run\n";
foreach ($config as $service_name => $service_id) {
echo date("r") . " - Pulling stats for {$service_name}...\n";
runStats($service_id, $service_name);
}
echo date("r") . " - Done\n";
?>