yannstatic/static/2020/09/28/InfluxDB-Telegraf-Grafana.html

2782 lines
245 KiB
HTML
Raw Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>InfluxDB Telegraf Grafana - YannStatic</title>
<meta name="description" content="Grafana">
<link rel="canonical" href="https://static.rnmkcy.eu/2020/09/28/InfluxDB-Telegraf-Grafana.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
<!-- - include head/favicon.html - -->
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
<!-- end custom head snippets --><script>(function() {
window.isArray = function(val) {
return Object.prototype.toString.call(val) === '[object Array]';
};
window.isString = function(val) {
return typeof val === 'string';
};
window.hasEvent = function(event) {
return 'on'.concat(event) in window.document;
};
window.isOverallScroller = function(node) {
return node === document.documentElement || node === document.body || node === window;
};
window.isFormElement = function(node) {
var tagName = node.tagName;
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
};
window.pageLoad = (function () {
var loaded = false, cbs = [];
window.addEventListener('load', function () {
var i;
loaded = true;
if (cbs.length > 0) {
for (i = 0; i < cbs.length; i++) {
cbs[i]();
}
}
});
return {
then: function(cb) {
cb && (loaded ? cb() : (cbs.push(cb)));
}
};
})();
})();
(function() {
window.throttle = function(func, wait) {
var args, result, thisArg, timeoutId, lastCalled = 0;
function trailingCall() {
lastCalled = new Date;
timeoutId = null;
result = func.apply(thisArg, args);
}
return function() {
var now = new Date,
remaining = wait - (now - lastCalled);
args = arguments;
thisArg = this;
if (remaining <= 0) {
clearTimeout(timeoutId);
timeoutId = null;
lastCalled = now;
result = func.apply(thisArg, args);
} else if (!timeoutId) {
timeoutId = setTimeout(trailingCall, remaining);
}
return result;
};
};
})();
(function() {
var Set = (function() {
var add = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (data[i] === item) {
return;
}
}
this.size ++;
data.push(item);
return data;
};
var Set = function(data) {
this.size = 0;
this._data = [];
var i;
if (data.length > 0) {
for (i = 0; i < data.length; i++) {
add.call(this, data[i]);
}
}
};
Set.prototype.add = add;
Set.prototype.get = function(index) { return this._data[index]; };
Set.prototype.has = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (this.get(i) === item) {
return true;
}
}
return false;
};
Set.prototype.is = function(map) {
if (map._data.length !== this._data.length) { return false; }
var i, j, flag, tData = this._data, mData = map._data;
for (i = 0; i < tData.length; i++) {
for (flag = false, j = 0; j < mData.length; j++) {
if (tData[i] === mData[j]) {
flag = true;
break;
}
}
if (!flag) { return false; }
}
return true;
};
Set.prototype.values = function() {
return this._data;
};
return Set;
})();
window.Lazyload = (function(doc) {
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
var createNode = function(name, attrs) {
var node = doc.createElement(name), attr;
for (attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
node.setAttribute(attr, attrs[attr]);
}
}
return node;
};
var end = function(type, url) {
var s, q, qi, cbs, i, j, cur, val, flag;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
s[url] = true;
for (i = 0; i < q.length; i++) {
cur = q[i];
if (cur.urls.has(url)) {
qi = cur, val = qi.urls.values();
qi && (cbs = qi.callbacks);
for (flag = true, j = 0; j < val.length; j++) {
cur = val[j];
if (!s[cur]) {
flag = false;
}
}
if (flag && cbs && cbs.length > 0) {
for (j = 0; j < cbs.length; j++) {
cbs[j].call(context);
}
qi.load = true;
}
}
}
}
};
var load = function(type, urls, callback) {
var s, q, qi, node, i, cur,
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
for (i = 0; i < q.length; i++) {
cur = q[i];
if (_urls.is(cur.urls)) {
qi = cur;
break;
}
}
val = _urls.values();
if (qi) {
callback && (qi.load || qi.callbacks.push(callback));
callback && (qi.load && callback());
} else {
q.push({
urls: _urls,
callbacks: callback ? [callback] : [],
load: false
});
for (i = 0; i < val.length; i++) {
node = null, url = val[i];
if (s[url] === undefined) {
(type === 'js' ) && (node = createNode('script', { src: url }));
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
if (node) {
node.onload = (function(type, url) {
return function() {
end(type, url);
};
})(type, url);
(doc.head || doc.body).appendChild(node);
s[url] = false;
}
}
}
}
}
};
return {
js: function(url, callback) {
load('js', url, callback);
},
css: function(url, callback) {
load('css', url, callback);
}
};
})(this.document);
})();
</script><script>
(function() {
var TEXT_VARIABLES = {
version: '2.2.6',
sources: {
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
jquery: '/assets/js/jquery.min.js',
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
gitalk: {
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
},
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
},
site: {
toc: {
selectors: 'h1,h2,h3'
}
},
paths: {
search_js: '/assets/search.js'
}
};
window.TEXT_VARIABLES = TEXT_VARIABLES;
})();
</script>
</head>
<body>
<div class="root" data-is-touch="false">
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
<div class="header__title">
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
<!-- Champ de recherche -->
<div id="searchbox" class="search search--dark" style="visibility: visible">
<div class="main">
<div class="search__header"></div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<!-- <div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div> -->
</div>
</div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
json: '/search.json',
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date}&nbsp;{title}</a></li>'
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a></li>'
})
</script>
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
2024-11-28 11:42:23 +01:00
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/syntaxe-markdown.html">Aide</a></li></ul>
2024-10-31 20:18:37 +01:00
</nav></div>
</header>
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">InfluxDB Telegraf Grafana</h1></header></div><meta itemprop="headline" content="InfluxDB Telegraf Grafana"><div class="article__info clearfix"><ul class="left-col menu"><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=application">application</a>
2024-10-31 20:18:37 +01:00
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">28&nbsp;sept.&nbsp;2020</span>
<span title="Modification" style="color:#00FF7F">18&nbsp;janv.&nbsp;2021</span></li></ul></div><meta itemprop="datePublished" content="2021-01-18T00:00:00+01:00">
<meta itemprop="keywords" content="application"><div class="js-article-content">
<div class="layout--article"><!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><h2 id="grafana">Grafana</h2>
<p><em><a href="https://grafana.com/grafana/download">Grafana</a> est un logiciel open-source qui transforme les multiples flux provenant de systèmes tels que Graphite, Telegraf, et InfluxDB en de magnifiques métriques dans un tableau de bord centralisé.</em></p>
<ul>
<li><a href="https://epervier.ovh/posts/20200621-metrologie_telegraf_influxdb_et_grafana/">Metrologie : Telegraf, influxdb et grafana</a></li>
</ul>
<h3 id="installer-grafana-debian">Installer Grafana (debian)</h3>
<p>En root</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt-get <span class="nb">install</span> <span class="nt">-y</span> apt-transport-https
apt-get <span class="nb">install</span> <span class="nt">-y</span> software-properties-common wget
wget <span class="nt">-q</span> <span class="nt">-O</span> - https://packages.grafana.com/gpg.key | apt-key add -
<span class="nb">echo</span> <span class="s2">"deb https://packages.grafana.com/oss/deb stable main"</span> <span class="o">&gt;</span> /etc/apt/sources.list.d/grafana.list
apt-get update
apt-get <span class="nb">install </span>grafana
systemctl daemon-reload
systemctl start grafana-server
systemctl status grafana-server
<span class="nb">sudo </span>systemctl <span class="nb">enable </span>grafana-server
</code></pre></div></div>
<p>linterface dadministration de Grafana est accessible à lURL <a href="http://lxcdeb:3000">http://lxcdeb:3000</a> <br />
<img src="/images/grafana001.png" alt="Grafana" width="700" /><br />
A la première connexion, seul un compte “admin” est créé, avec le mot de passe “admin”.<br />
<img src="/images/grafana002.png" alt="Grafana" width="700" /> <br />
Nouveau mot de passe : grafana49450</p>
<p>Pour créer les dashboards, vous pouvez récupérer des <a href="https://grafana.com/dashboards">dashboards de la communauté Grafana</a> ou créer vos propres dashboards.</p>
<h3 id="sécuriser-grafana">Sécuriser Grafana</h3>
<p><em>Désactiver les enregistrements et laccès anonyme à Grafana</em></p>
<p>Grafana offre des options qui permettent aux visiteurs de créer des comptes dutilisateurs pour eux-mêmes et de prévisualiser les tableaux de bord sans senregistrer. Lorsque Grafana nest pas accessible via Internet ou lorsque vous travaillez avec des données accessibles au public comme des statuts du service, vous pouvez vouloir autoriser ces fonctionnalités. Cependant, lorsque vous utilisez Grafana en ligne pour travailler avec des données sensibles, laccès anonyme peut poser un problème de sécurité. Pour résoudre ce problème, modifiez la configuration de Grafana.</p>
<p>Commencez par ouvrir le fichier de configuration principal de Grafana pour léditer :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/grafana/grafana.ini
</code></pre></div></div>
<p>Localisez la directive suivante `
` sous le titre <code class="language-plaintext highlighter-rouge">[users]</code> :</p>
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">...</span>
<span class="nn">[users]</span>
<span class="c"># disable user signup / registration
;allow_sign_up = true
</span><span class="err">...</span>
</code></pre></div></div>
<p><u>Activer cette directive</u> avec <code class="language-plaintext highlighter-rouge">true</code> ajoute un bouton <strong>Sign up</strong> à lécran de connexion ce qui permet aux utilisateurs de senregistrer et daccéder à Grafana.<br />
<u>Désactiver cette directive</u> avec <code class="language-plaintext highlighter-rouge">false</code> supprime le bouton Sign up et renforce la sécurité et la confidentialité de Grafana.</p>
<p>Désactiver cette directive en supprimant le <code class="language-plaintext highlighter-rouge">;</code> au début de la ligne puis en réglant loption sur <code class="language-plaintext highlighter-rouge">false</code> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
[users]
# disable user signup / registration
allow_sign_up = false
...
</code></pre></div></div>
<p>Ensuite, localisez la directive <code class="language-plaintext highlighter-rouge">enabled</code> suivante sous le titre <code class="language-plaintext highlighter-rouge">[auth.anonymous]</code> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
[auth.anonymous]
# enable anonymous access
;enabled = false
...
</code></pre></div></div>
<p>Définir <code class="language-plaintext highlighter-rouge">enabled</code> sur <code class="language-plaintext highlighter-rouge">true</code> donne aux utilisateurs non enregistrés accès à vos tableaux de bord, définir cette option sur <code class="language-plaintext highlighter-rouge">false</code> limite laccès du tableau de bord aux utilisateurs enregistrés seulement.</p>
<p>Décommentez cette directive en supprimant le <code class="language-plaintext highlighter-rouge">;</code> au début de la ligne puis en réglant loption sur <code class="language-plaintext highlighter-rouge">false</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
[auth.anonymous]
# enable anonymous access
enabled = false
...
</code></pre></div></div>
<p>Sauvegardez le fichier et quittez votre éditeur de texte.</p>
<p>Pour activer les changements, redémarrez Grafana :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart grafana-server
</code></pre></div></div>
<p>Vérifiez que tout fonctionne en vérifiant le statut service de Grafana :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl status grafana-server
</code></pre></div></div>
<p>Pour revenir à lécran dinscription, amenez votre curseur sur votre avatar en bas à gauche de lécran et cliquez sur loption Déconnexion qui apparaît.</p>
<p>Une fois que vous vous êtes déconnecté, vérifiez quil ny a pas de bouton Sign up et que vous ne pouvez pas vous connecter sans saisir des identifiants de connexion.</p>
<p>À ce stade, Grafana est entièrement configuré et prêt à être utilisé.</p>
<h2 id="influxdb-telegraf">InfluxDB Telegraf</h2>
<h3 id="influxdb">InfluxDB</h3>
<p><em>InfluxDB est une base de données de séries chronologiques Open Source conçue pour surveiller les mesures et les événements tout en offrant une visibilité en temps réel sur les piles. InfluxDB est un produit développé par InfluxData dans le cadre de TICK Stack - qui comprend Telegraf, InfluxDB, Chronograf et Kapacitor. Il sagit dune base de données de séries chronologiques à haute disponibilité.</em></p>
<p>installation dInfluxDB sur la distribution Linux Debian 10 (Buster)</p>
<p>Ajouter le dépôt APT InfluxDB.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> gnupg curl wget
wget <span class="nt">-qO-</span> https://repos.influxdata.com/influxdb.key | <span class="nb">sudo </span>apt-key add -
<span class="nb">echo</span> <span class="s2">"deb https://repos.influxdata.com/debian buster stable"</span> | <span class="nb">sudo tee</span> /etc/apt/sources.list.d/influxdb.list
</code></pre></div></div>
<p>Une fois le dépôt ajouté, installez InfluxDB sur Debian 10 (Buster) Linux :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> influxdb
<span class="nb">sudo </span>systemctl start influxdb
</code></pre></div></div>
<p>Le fichier de configuration par défaut dInfluxDB se trouve sous <code class="language-plaintext highlighter-rouge">/etc/influxdb/influxdb.conf</code>. La plupart des sections sont commentées, vous pouvez le modifier à votre convenance et redémarrer le service influxdb après.</p>
<p>Vérifiez létat du service :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl status influxdb
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● influxdb.service - InfluxDB is an open-source, distributed, time series database
Loaded: loaded (/lib/systemd/system/influxdb.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2020-12-24 10:47:56 CET; 5s ago
Docs: https://docs.influxdata.com/influxdb/
Main PID: 1520 (influxd)
Tasks: 13 (limit: 19030)
Memory: 7.3M
CGroup: /system.slice/influxdb.service
└─1520 /usr/bin/influxd -config /etc/influxdb/influxdb.conf
</code></pre></div></div>
<p>Si non actif (enabled)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl enable --now influxdb
</code></pre></div></div>
<p>Par défaut, InfluxDB utilise les ports réseau suivants :</p>
<ul>
<li>Le port TCP 8086 est utilisé pour la communication client-serveur via lAPI HTTP dInfluxDB</li>
<li>Le port TCP 8088 est utilisé pour le service RPC pour la sauvegarde et la restauration</li>
</ul>
<p>Configurer lauthentification http dInfluxDB (facultatif)<br />
Si vous avez besoin dune authentification http, modifiez la section influxdb http pour quelle contienne ce qui suit.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/influxdb/influxdb.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[http]
auth-enabled = true
</code></pre></div></div>
<p>Créez ensuite un utilisateur avec un mot de passe dauthentification :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -XPOST "http://localhost:8086/query" --data-urlencode "q=CREATE USER username WITH PASSWORD 'strongpassword' WITH ALL PRIVILEGES"
</code></pre></div></div>
<p>Remplacer :</p>
<ul>
<li><strong>username</strong> par votre propre nom dutilisateur</li>
<li><strong>strongpassword</strong> avec votre propre mot de passe (notez que le mot de passe nécessite des guillemets simples)</li>
</ul>
<p>Maintenant, chaque fois que vous devez exécuter des commandes influxdb sur le terminal, vous devez spécifier le nom dutilisateur en utilisant les options <code class="language-plaintext highlighter-rouge">-username</code> et mot de passe en utilisant <code class="language-plaintext highlighter-rouge">-password</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>influx -username 'username' -password 'password'
</code></pre></div></div>
<p>Pour le curl, utilisez <code class="language-plaintext highlighter-rouge">-u</code> pour spécifier le nom dutilisateur et le mot de passe séparés par deux points.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -G http://localhost:8086/query -u username:password --data-urlencode "q=SHOW DATABASES"
</code></pre></div></div>
<h3 id="telegraf">Telegraf</h3>
<p>Installer le package :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update &amp;&amp; sudo apt install telegraf
</code></pre></div></div>
<p>Vérifier le service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl status telegraf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● telegraf.service - The plugin-driven server agent for reporting metrics into InfluxDB
Loaded: loaded (/lib/systemd/system/telegraf.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2020-09-27 10:32:55 CEST; 32s ago
Docs: https://github.com/influxdata/telegraf
Main PID: 1218 (telegraf)
Tasks: 10 (limit: 19029)
Memory: 15.4M
CGroup: /system.slice/telegraf.service
└─1218 /usr/bin/telegraf -config /etc/telegraf/telegraf.conf -config-directory /etc/telegraf/te
</code></pre></div></div>
<p>Vérifier les journeaux</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo journalctl -f -u telegraf.service
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-- Logs begin at Sun 2020-09-27 08:34:07 CEST. --
sept. 27 10:32:55 debian-10 systemd[1]: Started The plugin-driven server agent for reporting metrics into InfluxDB.
sept. 27 10:32:55 debian-10 telegraf[1218]: 2020-09-27T08:32:55Z I! Starting Telegraf 1.15.3
sept. 27 10:32:55 debian-10 telegraf[1218]: 2020-09-27T08:32:55Z I! Loaded inputs: mem processes swap system cpu disk diskio kernel
sept. 27 10:32:55 debian-10 telegraf[1218]: 2020-09-27T08:32:55Z I! Loaded aggregators:
sept. 27 10:32:55 debian-10 telegraf[1218]: 2020-09-27T08:32:55Z I! Loaded processors:
sept. 27 10:32:55 debian-10 telegraf[1218]: 2020-09-27T08:32:55Z I! Loaded outputs: influxdb
sept. 27 10:32:55 debian-10 telegraf[1218]: 2020-09-27T08:32:55Z I! Tags enabled: host=debian-10
sept. 27 10:32:55 debian-10 telegraf[1218]: 2020-09-27T08:32:55Z I! [agent] Config: Interval:10s, Quiet:false, Hostname:"debian-10", Flush Interval:10s
</code></pre></div></div>
<h2 id="grafana---datasource">Grafana - datasource</h2>
<p>ATTENTION erreur service telegraf</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nov. 02 15:48:16 debian-10 telegraf[469]: 2020-11-02T14:48:16Z E! [outputs.influxdb] When writing to [https://127.0.0.1:8086]: Post "https://127.0.0.1:8086/write?db=telegraf": http: server gave HTTP response to HTTPS client
nov. 02 15:48:16 debian-10 telegraf[469]: 2020-11-02T14:48:16Z E! [agent] Error writing to outputs.influxdb: could not write any address
nov. 02 15:48:26 debian-10 telegraf[469]: 2020-11-02T14:48:26Z E! [outputs.influxdb] When writing to [https://127.0.0.1:8086]: Post "https://127.0.0.1:8086/write?db=telegraf": http: server gave HTTP response to HTTPS client
nov. 02 15:48:26 debian-10 telegraf[469]: 2020-11-02T14:48:26Z E! [agent] Error writing to outputs.influxdb: could not write any address
</code></pre></div></div>
<p>Il faut modifier le fichier <code class="language-plaintext highlighter-rouge">/etc/telegraf/telegraf.conf</code> , remplacer <code class="language-plaintext highlighter-rouge">urls = ["https://127.0.0.1:8086"]</code> par <code class="language-plaintext highlighter-rouge">urls = ["http://127.0.0.1:8086"]</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>###############################################################################
# OUTPUT PLUGINS #
###############################################################################
# Configuration for sending metrics to InfluxDB
[[outputs.influxdb]]
## The full HTTP or UDP URL for your InfluxDB instance.
##
## Multiple URLs can be specified for a single cluster, only ONE of the
## urls will be written to each interval.
# urls = ["unix:///var/run/influxdb.sock"]
# urls = ["udp://127.0.0.1:8089"]
urls = ["http://127.0.0.1:8086"]
</code></pre></div></div>
<p>Et redémarrer</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart telegraf
</code></pre></div></div>
<p>http://lxcdeb:3000 → Configuration → datasource → Add data source<br />
InfluxDb → Select → Save &amp; Test</p>
<h2 id="monitorer-son-débit-internet">Monitorer son débit internet</h2>
<h3 id="speedtest">speedtest</h3>
<p><a href="https://www.speedtest.net/">SPEEDTEST</a></p>
<p>Speedtest® CLI
Mesure de la connexion Internet pour les développeurs</p>
<p>Speedtest CLI apporte la technologie de confiance et le réseau mondial de serveurs derrière Speedtest à la ligne de commande. Conçu pour les développeurs de logiciels, les administrateurs système et les passionnés dinformatique, Speedtest CLI est la première application Speedtest officielle native de Linux et soutenue par Ookla®.</p>
<p>Avec Speedtest CLI, vous pouvez facilement :</p>
<ul>
<li>mesurer les performances de la connexion Internet, comme le téléchargement, le chargement, la latence et la perte de paquets, de manière native, sans avoir à utiliser un navigateur web</li>
<li>Testez la connexion internet de votre bureau Linux, dun serveur distant ou même dappareils moins puissants comme le Raspberry Pi® avec le serveur Speedtest Network™</li>
<li>Mettre en place des scripts automatisés pour collecter des données sur les performances de connexion, y compris les tendances dans le temps</li>
<li>Utilisez le Speedtest dans vos programmes en lenveloppant dans le langage de programmation de votre choix</li>
<li>Voir les résultats des tests via CSV, JSONL ou JSON</li>
</ul>
<blockquote>
<p>Le Speedtest CLI est maintenu par léquipe dOokla. Pour toute assistance, veuillez adresser vos demandes à <a href="mailto:support@ookla.com">support@ookla.com</a></p>
</blockquote>
<p><a href="https://www.speedtest.net/apps/cli">Télécharger lapplication</a> suivant votre matériel (i386, x86_64, arm32, arm32hf, et arm64)</p>
<p>On copie lexécutable <strong>speedtest</strong> dans le dossier <code class="language-plaintext highlighter-rouge">/usr/local/bin/</code></p>
<h3 id="alternative-a-defaut">Alternative A (DEFAUT)</h3>
<ul>
<li><a href="https://grafana.com/grafana/dashboards/12428">Internet Speed Test</a> et les <a href="https://github.com/Derek-K/telegraf-speedtest">instructions</a></li>
</ul>
<h4 id="speedtest-cli">Speedtest cli</h4>
<p>Installer le CLI officiel du SpeedTest depuis <strong><a href="https://www.speedtest.net/apps/cli">SpeedTest.net</a></strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt-get <span class="nb">install </span>gnupg apt-transport-https dirmngr
<span class="nb">export </span><span class="nv">INSTALL_KEY</span><span class="o">=</span>379CE192D401AB61
<span class="nb">sudo </span>apt-key adv <span class="nt">--keyserver</span> keyserver.ubuntu.com <span class="nt">--recv-keys</span> <span class="nv">$INSTALL_KEY</span>
<span class="nb">echo</span> <span class="s2">"deb https://ookla.bintray.com/debian generic main"</span> | <span class="nb">sudo tee</span> /etc/apt/sources.list.d/speedtest.list
<span class="nb">sudo </span>apt-get update
<span class="c"># Other non-official binaries will conflict with Speedtest CLI</span>
<span class="c"># Example how to remove using apt-get</span>
<span class="c"># sudo apt-get remove speedtest-cli</span>
<span class="nb">sudo </span>apt-get <span class="nb">install </span>speedtest
</code></pre></div></div>
<p>La commande <code class="language-plaintext highlighter-rouge">speedtest</code> sera exécutée avec les options et arguments suivants :</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">-f json</code>: spécifie le format de retour à json, nous facilitant lextraction par la suite</li>
<li><code class="language-plaintext highlighter-rouge">--accept-license</code>: pour accepter en non interactif la license dutilisation speedtest/Ookla</li>
<li><code class="language-plaintext highlighter-rouge">--accept-gdpr</code>: pour accepter en non interactif les conditions de conservation/utilisation des résultats par speedtest/Ookla</li>
</ul>
<p>Où est situé <code class="language-plaintext highlighter-rouge">speedtest</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>which speedtest
</code></pre></div></div>
<p>/usr/bin/speedtest</p>
<p>Effectuer un test de vitesse avec les arguments pour accepter la licence</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/bin/speedtest --accept-license --accept-gdpr
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>==============================================================================
License acceptance recorded. Continuing.
Speedtest by Ookla
Server: Axione - Paris (id = 28308)
ISP: Free SAS
Latency: 34.90 ms (0.63 ms jitter)
Download: 10.90 Mbps (data used: 19.3 MB)
Upload: 0.81 Mbps (data used: 1.1 MB)
Packet Loss: 1.0%
Result URL: https://www.speedtest.net/result/c/978f6083-8129-4366-bb4a-1adc6ff30d58
</code></pre></div></div>
<p>Test en json</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/bin/speedtest --accept-license --accept-gdpr -f json-pretty
</code></pre></div></div>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"result"</span><span class="p">,</span><span class="w">
</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-12-24T09:59:15Z"</span><span class="p">,</span><span class="w">
</span><span class="nl">"ping"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"jitter"</span><span class="p">:</span><span class="w"> </span><span class="mf">2.056</span><span class="p">,</span><span class="w">
</span><span class="nl">"latency"</span><span class="p">:</span><span class="w"> </span><span class="mf">34.777999999999999</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"download"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"bandwidth"</span><span class="p">:</span><span class="w"> </span><span class="mi">1345895</span><span class="p">,</span><span class="w">
</span><span class="nl">"bytes"</span><span class="p">:</span><span class="w"> </span><span class="mi">10270080</span><span class="p">,</span><span class="w">
</span><span class="nl">"elapsed"</span><span class="p">:</span><span class="w"> </span><span class="mi">7616</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"upload"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"bandwidth"</span><span class="p">:</span><span class="w"> </span><span class="mi">107936</span><span class="p">,</span><span class="w">
</span><span class="nl">"bytes"</span><span class="p">:</span><span class="w"> </span><span class="mi">957600</span><span class="p">,</span><span class="w">
</span><span class="nl">"elapsed"</span><span class="p">:</span><span class="w"> </span><span class="mi">9108</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"packetLoss"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"isp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Free SAS"</span><span class="p">,</span><span class="w">
</span><span class="nl">"interface"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"internalIp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2a01:e0a:2de:2c70:216:3eff:fea2:1955"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"eth0"</span><span class="p">,</span><span class="w">
</span><span class="nl">"macAddr"</span><span class="p">:</span><span class="w"> </span><span class="s2">"00:16:3E:A2:19:55"</span><span class="p">,</span><span class="w">
</span><span class="nl">"isVpn"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"externalIp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2a01:e0a:2de:2c70:216:3eff:fea2:1955"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"server"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">24215</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ORANGE FRANCE"</span><span class="p">,</span><span class="w">
</span><span class="nl">"location"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Paris"</span><span class="p">,</span><span class="w">
</span><span class="nl">"country"</span><span class="p">:</span><span class="w"> </span><span class="s2">"France"</span><span class="p">,</span><span class="w">
</span><span class="nl">"host"</span><span class="p">:</span><span class="w"> </span><span class="s2">"montsouris3.speedtest.orange.fr"</span><span class="p">,</span><span class="w">
</span><span class="nl">"port"</span><span class="p">:</span><span class="w"> </span><span class="mi">8080</span><span class="p">,</span><span class="w">
</span><span class="nl">"ip"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2a01:cb04:2004:4001::3"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"result"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"72d57f24-7e0e-4931-8156-2375eeafb0c0"</span><span class="p">,</span><span class="w">
</span><span class="nl">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://www.speedtest.net/result/c/72d57f24-7e0e-4931-8156-2375eeafb0c0"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>La définition de quelques champs du résultat</p>
<ul>
<li><em>result_id</em>: lid unique du test chez Speedtest/Ookla</li>
<li><em>ping_latency</em>: la latence du ping en millisecondes</li>
<li><em>download_bandwidth</em>: le débit descendant de notre connexion internet en bytes par secondes</li>
<li><em>upload_bandwidth</em>: le débit montant de notre connexion internet en bytes par secondes</li>
</ul>
<h4 id="speedtest-telegraf">Speedtest telegraf</h4>
<p>Ajouter la configuration <code class="language-plaintext highlighter-rouge">speedtest.conf</code> dans <strong>telegraf</strong> sous <code class="language-plaintext highlighter-rouge">/etc/telegraf/telegraf.d</code><br />
OU copier la configuration et lajouter à votre <code class="language-plaintext highlighter-rouge">telegraf.conf</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/telegraf/telegraf.d/speedtest.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#
# Install speedtest cli from SpeedTest.net first
# https://www.speedtest.net/apps/cli
#
# And then run speedtest once to accept the license
#
[[inputs.exec]]
commands = ["/usr/bin/speedtest --accept-license --accept-gdpr -f json-pretty"]
name_override = "Speedtest"
timeout = "1m"
interval = "15m"
data_format = "json"
json_string_fields = [ "interface_externalIp",
"server_name",
"server_location",
"server_host",
"server_ip",
"result_url" ]
</code></pre></div></div>
<p>Redémarrer le télégraphe <code class="language-plaintext highlighter-rouge">sudo systemctl restart telegraf</code></p>
<blockquote>
<p>p.s. Ne fixez pas lintervalle trop court ou vous risquez de vous faire interdire…</p>
</blockquote>
<h4 id="speedtest-influxdb-cli">Speedtest InfluxDB cli</h4>
<p>Un regard sur les données capturées</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>influx -username 'admin' -password 'xxxxx'
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Connected to http://localhost:8086 version 1.6.4
InfluxDB shell version: 1.6.4
<span class="o">&gt;</span> show databases
name: databases
name
<span class="nt">----</span>
_internal
telegraf
<span class="o">&gt;</span> use telegraf
Using database telegraf
<span class="o">&gt;</span> show measurements
name: measurements
name
<span class="nt">----</span>
Speedtest
cpu
disk
diskio
kernel
mem
processes
swap
system
<span class="o">&gt;</span> <span class="k">select</span> <span class="k">*</span> from Speedtest
name: Speedtest
<span class="nb">time </span>download_bandwidth download_bytes download_elapsed host interface_externalIp packetLoss ping_jitter ping_latency result_url server_host server_id server_ip server_location server_name server_port upload_bandwidth upload_bytes upload_elapsed
<span class="nt">----</span> <span class="nt">------------------</span> <span class="nt">--------------</span> <span class="nt">----------------</span> <span class="nt">----</span> <span class="nt">--------------------</span> <span class="nt">----------</span> <span class="nt">-----------</span> <span class="nt">------------</span> <span class="nt">----------</span> <span class="nt">-----------</span> <span class="nt">---------</span> <span class="nt">---------</span> <span class="nt">---------------</span> <span class="nt">-----------</span> <span class="nt">-----------</span> <span class="nt">----------------</span> <span class="nt">------------</span> <span class="nt">--------------</span>
1608804922000000000 1330911 9692912 7310 lxcbuster 82.64.18.243 0 0.623 34.966 https://www.speedtest.net/result/c/6dcb9c8d-207f-4cb0-9e4a-0f3d044ef120 lg.par-c.fdcservers.net 6027 198.16.112.250 Paris fdcservers.net 8080 105766 907896 8913
<span class="o">&gt;</span>QUIT
</code></pre></div></div>
<h4 id="speedtest-grafana">Speedtest grafana</h4>
<p>Pour vous connecter a linterface web de Grafana, rendez vous à lurl <a href="http://lxcdeb:3000/">http://lxcdeb:3000/</a><br />
Saisir le mot de passe de lutilisateur <strong>admin</strong></p>
<p>Source de données InfluxDB<br />
Depuis laccueil de Grafana, sélectionnez <strong>Add your first data source</strong> ou rendez-vous à lurl <a href="http://lxcdeb:3000/datasources/new">http://lxcdeb:3000/datasources/new</a> <br />
<img src="/images/grafana003.png" alt="Grafana" width="700" /><br />
Sélectionnez ensuite InfluxDb</p>
<p>Sur la page configuration de la data source, il faut renseigner</p>
<ul>
<li>url <a href="http://localhost:8086">http://localhost:8086</a> dans la section “HTTP”</li>
<li>Auth → Basic auth</li>
<li>User admin et password xxxx</li>
<li>Database : nom de la base de données <strong>telegraf</strong> dans la section “InfluxDB Details”.</li>
</ul>
<p><img src="/images/grafana004.png" alt="Grafana" width="400" /><br />
Vous pouvez alors sauvegarder et tester la connexion (bouton “Save &amp; Test”).<br />
Si tout est ok, le message <strong>Data source working</strong> saffiche.</p>
<p>Le dashboard</p>
<p><strong>Option A</strong><br />
<a href="https://github.com/risb0r/telegraf-speedtest">telegraf-speedtest</a> et copier le json <a href="https://raw.githubusercontent.com/risb0r/telegraf-speedtest/master/Speedtest.net-metrics.json">https://raw.githubusercontent.com/risb0r/telegraf-speedtest/master/Speedtest.net-metrics.json</a><br />
Dans le menu survolez le + (Create) puis sélectionnez “Import”.
collez le dans la zone “Import via panel json”<br />
<img src="/images/grafana005.png" alt="Grafana" width="700" /><br />
puis chargez le (bouton “Load”).<br />
<img src="/images/grafana006.png" alt="Grafana" width="700" /></p>
<p>Aperçu<br />
<img src="/images/grafana007.png" alt="Grafana" width="700" /></p>
<p><strong>Option B</strong><br />
<a href="https://grafana.com/grafana/dashboards/12428">Internet Speed Test</a> et les <a href="https://github.com/Derek-K/telegraf-speedtest">instructions</a></p>
<p>ID <a href="https://grafana.com/grafana/dashboards/12428">tableau de bord Grafana</a> correspondant : 12428 (<a href="https://grafana.com/api/dashboards/12428/revisions/1/download">le fichier json</a>)</p>
<p>Configurer grafana <a href="http://lxcdeb:3000">http://lxcdeb:3000</a><br />
Cliquer sur le <strong>+ → Import</strong><br />
<img src="/images/speedtest-dashboard.png" alt="speedtest-dashboard" width="300" /><br />
Saisir <strong>ID</strong> et cliquer sur <strong>Load</strong><br />
<img src="/images/speedtest-dashboard1.png" alt="speedtest-dashboard" width="400" /><br />
UID=ysbKIhiGk</p>
<p><img src="/images/speedtest-dashboard3.png" alt="speedtest-dashboard" width="600" /><br />
http://lxcdeb:3000/d/ysbKIhiGk/internet-speed-test?orgId=1</p>
<blockquote>
<p><strong>Veuillez changer sur chaque panneau, la valeur “host” dans la requête par votre nom dhôte</strong></p>
</blockquote>
<h3 id="alternative-b">Alternative B</h3>
<ul>
<li><a href="https://blog.eleven-labs.com/fr/monitorer-son-debit-internet/">Monitorer son débit internet</a></li>
</ul>
<h4 id="le-script-sous-pc1-archlinux">Le script sous “PC1 Archlinux”</h4>
<p>Récupération des mesures via <strong>speedtest.sh</strong> (PC1 Archlinux : <code class="language-plaintext highlighter-rouge">~/media/devel/yannick/speedtest-cli-x86_64/</code>) puis écriture dans la base <strong>speedtest</strong> de InfluxDB</p>
<p>Le script sous “PC1 Archlinux”</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano ~/media/devel/yannick/speedtest-cli-x86_64/speedtest.sh
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="c"># InfluxDB variables</span>
<span class="nv">influxdb_proto</span><span class="o">=</span><span class="k">${</span><span class="nv">INFLUXDB_PROTO</span><span class="k">:-</span><span class="nv">http</span><span class="k">}</span>
<span class="nv">influxdb_host</span><span class="o">=</span><span class="k">${</span><span class="nv">INFLUXDB_HOST</span><span class="k">:-</span><span class="nv">lxcdeb</span><span class="k">}</span>
<span class="nv">influxdb_port</span><span class="o">=</span><span class="k">${</span><span class="nv">INFLUXDB_PORT</span><span class="k">:-</span><span class="nv">8086</span><span class="k">}</span>
<span class="nv">influxdb_db</span><span class="o">=</span><span class="k">${</span><span class="nv">INFLUXDB_DB</span><span class="k">:-</span><span class="nv">speedtest</span><span class="k">}</span>
<span class="nv">influxdb_url</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">influxdb_proto</span><span class="k">}</span><span class="s2">://</span><span class="k">${</span><span class="nv">influxdb_host</span><span class="k">}</span><span class="s2">:</span><span class="k">${</span><span class="nv">influxdb_port</span><span class="k">}</span><span class="s2">"</span>
<span class="c"># run speedtest &amp; store result</span>
<span class="nv">json_result</span><span class="o">=</span><span class="si">$(</span>speedtest <span class="nt">-f</span> json <span class="nt">--accept-license</span> <span class="nt">--accept-gdpr</span><span class="si">)</span>
<span class="c"># Extract data from speedtest result</span>
<span class="nv">result_id</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">json_result</span><span class="k">}</span><span class="s2">"</span> | jq <span class="nt">-r</span> <span class="s1">'.result.id'</span><span class="si">)</span>
<span class="nv">ping_latency</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">json_result</span><span class="k">}</span><span class="s2">"</span> | jq <span class="nt">-r</span> <span class="s1">'.ping.latency'</span><span class="si">)</span>
<span class="nv">download_bandwidth</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">json_result</span><span class="k">}</span><span class="s2">"</span> | jq <span class="nt">-r</span> <span class="s1">'.download.bandwidth'</span><span class="si">)</span>
<span class="nv">upload_bandwidth</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">json_result</span><span class="k">}</span><span class="s2">"</span> | jq <span class="nt">-r</span> <span class="s1">'.upload.bandwidth'</span><span class="si">)</span>
<span class="c"># Ensure InfluxDB database exists</span>
curl <span class="se">\</span>
<span class="nt">-d</span> <span class="s2">"q=CREATE DATABASE </span><span class="k">${</span><span class="nv">influxdb_db</span><span class="k">}</span><span class="s2">"</span> <span class="se">\</span>
<span class="s2">"</span><span class="k">${</span><span class="nv">influxdb_url</span><span class="k">}</span><span class="s2">/query"</span>
<span class="c"># Write metric to InfluxDB</span>
curl <span class="se">\</span>
<span class="nt">-d</span> <span class="s2">"speedtest,result_id=</span><span class="k">${</span><span class="nv">result_id</span><span class="k">}</span><span class="s2"> ping_latency=</span><span class="k">${</span><span class="nv">ping_latency</span><span class="k">}</span><span class="s2">,download_bandwidth=</span><span class="k">${</span><span class="nv">download_bandwidth</span><span class="k">}</span><span class="s2">,upload_bandwidth=</span><span class="k">${</span><span class="nv">upload_bandwidth</span><span class="k">}</span><span class="s2">"</span> <span class="se">\</span>
<span class="s2">"</span><span class="k">${</span><span class="nv">influxdb_url</span><span class="k">}</span><span class="s2">/write?db=</span><span class="k">${</span><span class="nv">influxdb_db</span><span class="k">}</span><span class="s2">"</span>
</code></pre></div></div>
<p>On commence par définir les variables permettant la communication avec InfluxDB :</p>
<ul>
<li><strong>influxdb_proto</strong>: le protocole de communication avec InfluxDB, par défaut http, surchargeable par la variable denvironnement INFLUXDB_PROTO</li>
<li><strong>influxdb_host</strong>: le hostname du conteneur InfluxDB, par défaut localhost, surchargeable par la variable denvironnement INFLUXDB_HOST</li>
<li><strong>influxdb_port</strong>: le port découte du conteneur InfluxDB, par défaut 8086, surchargeable par la variable denvironnement INFLUXDB_PORT</li>
<li><strong>influxdb_db</strong>: le nom de la base de données InfluxDB à utiliser, par défaut speedtest, surchargeable par la variable denvironnement INFLUXDB_DB</li>
</ul>
<p>Lensemble de ces variables étant ensuite concaténé afin de produire lurl permettant la communication avec InfluxDB</p>
<p>Ensuite on stocke dans une variable le résultat de la commande <code class="language-plaintext highlighter-rouge">speedtest</code> exécutée avec les options et arguments :</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">-f json</code>: spécifie le format de retour à json, nous facilitant lextraction par la suite</li>
<li><code class="language-plaintext highlighter-rouge">--accept-license</code>: pour accepter en non interactif la license dutilisation speedtest/Ookla</li>
<li><code class="language-plaintext highlighter-rouge">--accept-gdpr</code>: pour accepter en non interactif les conditions de conservation/utilisation des résultats par speedtest/Ookla</li>
</ul>
<p>Une fois notre résultat récupéré, nous utilisons lutilitaire jq pour extraire les informations qui nous intéressent :</p>
<ul>
<li><em>result_id</em>: lid unique du test chez Speedtest/Ookla</li>
<li><em>ping_latency</em>: la latence du ping en millisecondes</li>
<li><em>download_bandwidth</em>: le débit descendant de notre connexion internet en bytes par secondes</li>
<li><em>upload_bandwidth</em>: le débit montant de notre connexion internet en bytes par secondes</li>
</ul>
<p>Maintenant que nous avons toutes les informations qui nous intéressent dans des variables, assurons-nous que la base de données InfluxDB speedtest existe en forçant la création si celle-ci nexiste pas en exécutant la query <code class="language-plaintext highlighter-rouge">CREATE DATABASE ${influx_db}</code> sur le endpoint <code class="language-plaintext highlighter-rouge">/query</code> dInfluxDB.</p>
<p>Puis pour finir écrivons dans cette base de données nos résultats sur le endpoint <code class="language-plaintext highlighter-rouge">/write</code> dInfluxDB en précisant le nom de notre base de données <code class="language-plaintext highlighter-rouge">?db=${influxdb_db}</code>, avec la data <code class="language-plaintext highlighter-rouge">speedtest,result_id=${result_id} ping_latency=${ping_latency},download_bandwidth=${download_bandwidth},upload_bandwidth=${upload_bandwidth}</code></p>
<blockquote>
<p><strong>NOTE :</strong> La base InfluxDB est accesible sur lurl <a href="http://lxcdeb:8086">http://lxcdeb:8086</a> (/etc/hosts → <code class="language-plaintext highlighter-rouge">10.0.3.19 lxcdeb</code>) <br />
Plus dinformations sur lécriture dans InfluxDB sont disponibles dans la <a href="https://docs.influxdata.com/influxdb/v1.8/guides/write_data/">documentation officielle</a></p>
</blockquote>
<p>Les droits dexécution sur ce script</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chmod +x ~/media/devel/yannick/speedtest-cli-x86_64/speedtest.sh
</code></pre></div></div>
<h4 id="séquenceur-a-voir">Séquenceur (A VOIR)</h4>
<p>Une mesure toutes les 15 minutes qui permet une bonne visibilité sans trop charger le réseau.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab -e
</code></pre></div></div>
<p>Et ajoutez en fin de fichier la ligne suivante avant de sauvegarder</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*/15 * * * * commande-a-executer
</code></pre></div></div>
<p>Cela signifie que toutes les 15 minutes (*/15 * * * *), la commande <strong>xxxx</strong> sera exécutée.x</p>
<h2 id="monitorer-une-structure">Monitorer une structure</h2>
<p><em>Monitorer une structure avec Telegraf, InfluxDB et Grafana</em></p>
<ul>
<li><a href="https://blog.octo.com/monitorer-votre-infra-avec-telegraf-influxdb-et-grafana/">Monitorer votre infra avec Telegraf, InfluxDB et Grafana</a></li>
<li><a href="https://devconnected.com/how-to-setup-telegraf-influxdb-and-grafana-on-linux/">How To Setup Telegraf InfluxDB and Grafana on Linux</a></li>
</ul>
<p>Parmi tous les outils de surveillance modernes existants, la pile TIG (Telegraf, InfluxDB et Grafana) est probablement lune des plus populaires.</p>
<p>Cette pile peut être utilisée pour surveiller un large éventail de sources de données différentes : des systèmes dexploitation (tels que Linux ou les mesures de performance de Windows) aux bases de données (telles que MongoDB ou MySQL), les possibilités sont infinies.</p>
<p>Le principe de la pile TIG est facile à comprendre.<br />
<strong>Telegraf</strong> est un agent chargé de collecter et dagréger les données, comme lutilisation actuelle du processeur par exemple.<br />
<strong>InfluxDB</strong> va stocker les données, et les exposer à <strong>Grafana</strong>, qui est une solution moderne de tableau de bord.</p>
<p><img src="/images/modern-monitoring-architecture.png" alt="Texte alternatif" width="600" /></p>
<h3 id="influxdb-telegraf-et-grafana">InfluxDB, Telegraf et Grafana</h3>
<p>Les applications InfluxDB, Telegraf et Grafana sont installées…</p>
<h3 id="authentification-influxdb-http-basic">Authentification InfluxDB HTTP Basic</h3>
<p>Pour avoir une configuration correcte de la pile TIG, mettre en place lauthentification InfluxDB pour que les utilisateurs soient connectés lors de laccès au serveur InfluxDB.</p>
<p><strong>1 - Créer un compte administrateur</strong><br />
Avant dactiver lauthentification HTTP, il faut un <strong>compte administrateur</strong>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>influx -execute "CREATE USER admin WITH PASSWORD 'admin49450' WITH ALL PRIVILEGES"
influx -execute "SHOW USERS"
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user admin
---- -----
admin true
</code></pre></div></div>
<p><strong>2 - Créer un compte pour Telegraf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>influx -execute "CREATE USER telegraf WITH PASSWORD 'telegraf49450' WITH ALL PRIVILEGES"
influx -execute "SHOW USERS"
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user admin
---- -----
admin true
telegraf true
</code></pre></div></div>
<p><strong>3 - Activer lauthentification HTTP sur votre serveur InfluxDB</strong> <br />
Lauthentification HTTP doit être activée dans le fichier de configuration InfluxDB.</p>
<p>Dans le fichier <code class="language-plaintext highlighter-rouge">/etc/influxdb/influxdb.conf</code> et modifier les lignes suivantes.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[...]
[http]
# Determines whether HTTP endpoint is enabled.
enabled = true
# The bind address used by the HTTP service.
bind-address = ":8086"
# Determines whether user authentication is enabled over HTTP/HTTPS.
auth-enabled = true
[...]
</code></pre></div></div>
<p><strong>4 - Configurer lauthentification HTTP sur Telegraf</strong> <br />
Maintenant quun compte dutilisateur est créé pour le Telegraf, nous allons nous assurer quil lutilise pour écrire des données.<br />
Modifier dans le fichier de configuration Telegraf <code class="language-plaintext highlighter-rouge">/etc/telegraf/telegraf.conf</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## HTTP Basic Auth
username = "telegraf"
password = "telegraf49450"
</code></pre></div></div>
<p>Redémarrer les services Telegraf InfluxDB</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl restart influxdb
<span class="nb">sudo </span>systemctl restart telegraf
</code></pre></div></div>
<p>Vérifiez à nouveau que vous nobtenez pas derreurs lors du redémarrage du service.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo journalctl -f -u telegraf.service
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-- Logs begin at Sun 2020-09-27 08:34:07 CEST. --
sept. 27 13:33:05 debian-10 systemd[1]: telegraf.service: Succeeded.
sept. 27 13:33:05 debian-10 systemd[1]: Stopped The plugin-driven server agent for reporting metrics into InfluxDB.
sept. 27 13:33:05 debian-10 systemd[1]: Started The plugin-driven server agent for reporting metrics into InfluxDB.
sept. 27 13:33:05 debian-10 telegraf[1583]: 2020-09-27T11:33:05Z I! Starting Telegraf 1.15.3
sept. 27 13:33:05 debian-10 telegraf[1583]: 2020-09-27T11:33:05Z I! Loaded inputs: swap system cpu disk diskio kernel mem processes
sept. 27 13:33:05 debian-10 telegraf[1583]: 2020-09-27T11:33:05Z I! Loaded aggregators:
sept. 27 13:33:05 debian-10 telegraf[1583]: 2020-09-27T11:33:05Z I! Loaded processors:
sept. 27 13:33:05 debian-10 telegraf[1583]: 2020-09-27T11:33:05Z I! Loaded outputs: influxdb
sept. 27 13:33:05 debian-10 telegraf[1583]: 2020-09-27T11:33:05Z I! Tags enabled: host=debian-10
sept. 27 13:33:05 debian-10 telegraf[1583]: 2020-09-27T11:33:05Z I! [agent] Config: Interval:10s, Quiet:false, Hostname:"debian-10", Flush Interval:10s
</code></pre></div></div>
<h3 id="authentification-influxdb-https">Authentification InfluxDB HTTPS</h3>
<p><em>La configuration de protocoles sécurisés entre Telegraf et InfluxDB est une étape très importante.</em></p>
<p>Si vos instances Telegraf fonctionnent à distance (sur un Raspberry Pi par exemple), la sécurisation du transfert de données est une étape obligatoire car il y a de très fortes chances que quelquun puisse lire les données que vous envoyez.</p>
<p><strong>1 - Créez une clé privée pour votre serveur InfluxDB</strong><br />
Tout dabord, installez le paquet gnutls-utils qui peut être fourni sous forme de gnutls-bin sur les distributions Debian par exemple.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install gnutls-bin
</code></pre></div></div>
<p>Maintenant que vous avez installé le certtool, générez une clé privée pour votre serveur InfluxDB</p>
<p>Créer un nouveau dossier pour InfluxDB dans le dossier <code class="language-plaintext highlighter-rouge">/etc/ssl</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo mkdir</span> /etc/ssl/influxdb <span class="o">&amp;&amp;</span> <span class="nb">cd</span> /etc/ssl/influxdb
<span class="nb">sudo </span>certtool <span class="nt">--generate-privkey</span> <span class="nt">--outfile</span> server-key.pem <span class="nt">--sec-param</span> High
</code></pre></div></div>
<p><em>Generating a 3072 bit RSA private key…</em></p>
<p><strong>2 - Créer un certificat racine pour le serveur InfluxDB</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo certtool --generate-self-signed --load-privkey server-key.pem --outfile server-cert.pem
</code></pre></div></div>
<p>Des questions sont posées, pour enregistrer dans le certificat des informations utiles pourse souvenir de qui gère cette autorité.<br />
Voici les informations importantes à saisir. Pour lesautres questions, vous pouvez garder les réponses par défaut, en laissant la réponse vide et en tapant enter</p>
<ul>
<li>Common name : CAInfluxDB</li>
<li>The certificate will expire in (days) : 2000</li>
<li>Does the certificate belong to an authority ? (y/N) : y</li>
<li>Will the certificate be used to sign other certificates ? (y/N) : y</li>
<li>Is the above information ok ? (y/N) : y</li>
</ul>
<blockquote>
<p><strong>Note :</strong> le common name permet didentifier lautorité de certification, pour que le client sache plus tard à qui il a envie de faire confiance ou non.<br />
On peut revoir le contenu du certificat à laide de :<br />
<code class="language-plaintext highlighter-rouge">certtool --certificate-info --infile ca.crt</code><br />
ou bien juste son empreinte (fingerprint) :<br />
<code class="language-plaintext highlighter-rouge">certtool --infile ca.crt --fingerprint</code><br />
Le fichier <code class="language-plaintext highlighter-rouge">ca.key</code> est la partie privée du certificat, à ne pas divulguer à qui que ce soit dautre. Cest justement là que sappuie lautorité : seul celui qui connait le contenu de <code class="language-plaintext highlighter-rouge">ca.key</code> pourra créer des certificats.
<code class="language-plaintext highlighter-rouge">ca.crt</code> est par contre le certificat racine, à diffuser aux clients.</p>
</blockquote>
<p>Noubliez pas de définir les permissions pour lutilisateur et le groupe InfluxDB.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chown influxdb:influxdb /etc/ssl/influxdb/{server-key.pem,server-cert.pem}
</code></pre></div></div>
<p>Validité des certificats</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl x509 -in /etc/ssl/influxdb/server-cert.pem -text |grep Not
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Not Before: Sep 27 12:05:45 2020 GMT
Not After : Mar 20 12:05:59 2026 GMT
</code></pre></div></div>
<p><strong>3 - Activer le HTTPS sur votre serveur InfluxDB</strong><br />
Maintenant que vos certificats sont créés, il est temps de modifier notre fichier de configuration InfluxDB <code class="language-plaintext highlighter-rouge">/etc/influxdb/influxdb.conf</code> pour activer le HTTPS.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Determines whether HTTPS is enabled.
https-enabled = true
# The SSL certificate to use when HTTPS is enabled.
https-certificate = "/etc/ssl/influxdb/server-cert.pem"
# Use a separate private key location.
https-private-key = "/etc/ssl/influxdb/server-key.pem"
</code></pre></div></div>
<p>Redémarrez le service InfluxDB et assurez-vous que vous nobtenez aucune erreur.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl restart influxdb
<span class="nb">sudo </span>journalctl <span class="nt">-f</span> <span class="nt">-u</span> influxdb.service
</code></pre></div></div>
<p><strong>4 - Configurer le telegraf pour le HTTPS</strong><br />
Maintenant que le HTTPS est disponible sur le serveur InfluxDB, il est temps pour Telegraf datteindre InfluxDB via HTTPS.Dans le fichier <code class="language-plaintext highlighter-rouge">/etc/telegraf/telegraf.conf</code> ,modifier les lignes suivantes.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Configuration for sending metrics to InfluxDB
[[outputs.influxdb]]
# https, not http!
urls = ["https://127.0.0.1:8086"]
## Use TLS but skip chain &amp; host verification
insecure_skip_verify = true
</code></pre></div></div>
<blockquote>
<p>Pourquoi avons-nous activé le paramètre <code class="language-plaintext highlighter-rouge">insecure_skip_verify</code> ?<br />
Parce que nous utilisons un <strong>certificat auto-signé</strong>.<br />
Par conséquent, lidentité du serveur InfluxDB nest pas certifiée par une autorité de certification. Si vous voulez un exemple de ce à quoi ressemble une authentification TLS complète, assurez-vous de lire le guide de la journalisation centralisée sous Linux <a href="https://devconnected.com/the-definitive-guide-to-centralized-logging-with-syslog-on-linux/#V_Encrypting_rsyslog_messages_with_TLS">guide to centralized logging on Linux.</a>.</p>
</blockquote>
<p>Redémarrez Telegraf, et assurez-vous à nouveau que vous nobtenez aucune erreur.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl restart telegraf
<span class="nb">sudo </span>journalctl <span class="nt">-f</span> <span class="nt">-u</span> telegraf.service
</code></pre></div></div>
<h3 id="influxdb-cli-explorer-vos-mesures">InfluxDB (cli), explorer vos mesures</h3>
<p>Avant dinstaller Grafana et de créer notre premier tableau de bord Telegraf, jetons un coup dœil rapide à la façon dont Telegraf regroupe nos mesures.</p>
<p>Par défaut, pour les systèmes Linux, Telegraf commencera à rassembler les données relatives aux performances de votre système via des plugins nommés cpu, disk, diskio, kernel, mem, processes, swap et system.</p>
<p>Les noms sont assez explicites, ces plugins rassemblent des données sur lutilisation du processeur, de la mémoire ainsi que sur les opérations de lecture et décriture des E/S sur le disque.</p>
<blockquote>
<p>Vous cherchez un tutoriel dédié aux entrées/sorties de disques ? Voici comment configurer Grafana et Prometheus pour surveiller les entrées/sorties de disques en temps réel (<a href="https://devconnected.com/monitoring-disk-i-o-on-linux-with-the-node-exporter/">Heres how to setup Grafana and Prometheus to monitor Disk I/O in real time</a>).</p>
</blockquote>
<p>Jetons un coup doeil rapide à lune des mesures.</p>
<p>Pour ce faire, utilisez le CLI InfluxDB avec les paramètres suivants.</p>
<p>Les données sont stockées dans la base de données “telegraf”, chaque mesure étant nommée comme le nom du plugin dentrée.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>influx -ssl -unsafeSsl -username 'admin' -password 'admin49450'
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Connected to https://localhost:8086 version 1.6.4
InfluxDB shell version: 1.6.4
&gt; USE telegraf
Using database telegraf
&gt; SELECT * FROM cpu WHERE time &gt; now() - 30s
name: cpu
time cpu host usage_guest usage_guest_nice usage_idle usage_iowait usage_irq usage_nice usage_softirq usage_steal usage_system usage_user
---- --- ---- ----------- ---------------- ---------- ------------ --------- ---------- ------------- ----------- ------------ ----------
1601209930000000000 cpu-total debian-10 0 0 93.91943248037752 0 0.12667848999247106 0 0.05067139599696682 0 0.17734988598925785 5.725867747658943
1601209930000000000 cpu0 debian-10 0 0 92.08121827412232 0 0.2030456852792135 0 0 0 0.20304568527903313 7.512690355331151
1601209930000000000 cpu1 debian-10 0 0 92.10526315790443 0 0.10121457489879213 0 0.10121457489882808 0 0.10121457489872021 7.591093117410919
1601209930000000000 cpu2 debian-10 0 0 94.42755825735229 0 0.20263424518741727 0 0 0 0.10131712259363665 5.268490374873713
[...]
</code></pre></div></div>
<p>Les données sont correctement agrégées sur le serveur InfluxDB.</p>
<h3 id="dashboard-grafana">Dashboard Grafana</h3>
<p>On suppose que Grafana est préalablement installé…
Accès par le lien <a href="http://lxcdeb:3000">http://lxcdeb:3000</a>, saisie “admin” et son mot de passe “grafana49450”</p>
<p><strong>1 - Ajouter InfluxDB comme source de données sur Grafana</strong><br />
Dans le menu de gauche, cliquez sur la section <strong>Configuration &gt; Data sources</strong><br />
<img src="/images/config-datasource.png" alt="grafana" width="150" /></p>
<p>Dans la fenêtre suivante, cliquez sur “Add datasource”.<br />
<img src="/images/add-data-source.png" alt="Bouton &quot;Ajouter une source de données&quot; à Grafana" width="600" /></p>
<p>Dans le panneau de sélection des sources de données, choisissez InfluxDB comme source de données.<br />
<img src="/images/influxdb-option.png" alt="Option de source de données InfluxDB dans Grafana" width="600" /></p>
<p>Voici la configuration à respecter pour configurer InfluxDB sur Grafana.<br />
<img src="/images/influxdb-config.png" alt="grafana" width="600" /> <br />
<img src="/images/influxdb-config-1.png" alt="grafana" width="600" /></p>
<p>Cliquez sur “Save &amp; Test”, et assurez-vous que vous nobtenez aucune erreur.<br />
<img src="/images/data-source-is-working.png" alt="grafana" width="600" /></p>
<p><code class="language-plaintext highlighter-rouge">502 Bad Gateway error</code> ? Assurez-vous que le champ de votre URL est défini sur HTTPS et non sur HTTP.</p>
<p><strong>2 - Importation dun tableau de bord Grafana</strong><br />
Nous nallons pas créer un tableau de bord Grafana pour le Telegraf, nous allons utiliser un tableau de bord préexistant déjà développé par la communauté.</p>
<p>Pour importer un tableau de bord Grafana, sélectionnez loption <strong>Import</strong> dans le menu de gauche, sous licône Plus.<br />
<img src="/images/import-dashboard.png" alt="grafana" width="150" /> <br />
Sur lécran suivant, importez le tableau de bord avec lidentifiant 8451.<br />
Il sagit dun tableau de bord créé par <a href="https://gabrielsagnard.fr/">Gabriel Sagnard</a> qui affiche les mesures du système collectées par Telegraf.<br />
<img src="/images/import-dashboard-23.png" alt="grafana" width="200" /> <br />
De là, Grafana devrait automatiquement essayer dimporter ce tableau de bord.</p>
<p>Ajoutez lInfluxDB configuré précédemment comme source de données du tableau de bord et cliquez sur “Importer”.<br />
<img src="/images/import-dashboard-3.png" alt="Sélection d'InfluxDB comme source de données dans Grafana" width="300" /></p>
<p>Nous avons maintenant notre premier tableau de bord Grafana affichant les mesures du Telegraf.<br />
Cest ce que vous devriez maintenant voir sur votre écran.<br />
<img src="/images/final-dashboard.png" alt="Tableau de bord Grafana affichant les mesures du Telegraf" width="600" /></p>
<p><strong>3 - Modification des requêtes InfluxQL dans lexplorateur de requêtes Grafana</strong></p>
<p>Lors de la conception de ce tableau de bord, le créateur a spécifié le nom dhôte “nagisa”, qui est évidemment différent dun hôte à lautre (le mien est par exemple nommé “debian-10”)</p>
<p>Pour le modifier, allez dans lexplorateur de requêtes en survolant le titre du panneau et en cliquant sur “Modifier”. <br />
<img src="/images/edit-dashboard.png" alt="grafana" width="400" /></p>
<p>Dans le panneau “Query”, changez dhôte, et le panneau devrait commencer à afficher des données.<br />
<img src="/images/edit-dashboard-1.png" alt="Requête InfluxDB dans Grafana" /> <br />
Ne pas oublier de sauvegarder !</p>
<p>Retournez au tableau de bord, et voici ce que vous devriez voir.<br />
<img src="/images/cpu-dashboard.png" alt="Tableau de bord CPU à Grafana" width="600" /><br />
UUID LmTA89zmk</p>
<p>http://lxcdeb:3000/d/LmTA89zmk/influxdb-telegraf?orgId=1&amp;refresh=1m</p>
<h3 id="conclusion">Conclusion</h3>
<p>Dans ce tutoriel, vous avez appris à installer une pile complète Telegraf, InfluxDB et Grafana sur votre serveur.</p>
<p>Alors, que devez-vous faire à partir de là ?</p>
<p>La première chose à faire serait de connecter Telegraf à <a href="https://docs.influxdata.com/telegraf/v1.11/plugins/plugin-list/">différentes entrées</a>, de rechercher les <a href="https://grafana.com/grafana/dashboards">tableaux de bord existants dans Grafana</a> ou de concevoir vos propres tableaux de bord.</p>
<p>Saviez-vous par exemple que vous pouviez <a href="https://devconnected.com/geolocating-ssh-hackers-in-real-time/">surveiller les hackers SSH en temps réel avec la pile TIG</a> ?</p>
<h3 id="dépannage">Dépannage</h3>
<p><code class="language-plaintext highlighter-rouge">Error writing to output [influxdb] : could not write any address</code><br />
<img src="/images/error-output-telegraf.png" alt="error-output-telegraf.png" /><br />
<strong>Solution possible</strong> : sassurer quInfluxDB fonctionne correctement sur le port 8086.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install lsof
sudo lsof -i -P -n | grep influxdb
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>influxd 17737 influxdb 128u IPv6 1177009213 0t0 TCP *:8086 (LISTEN)
</code></pre></div></div>
<p>Si vous avez un port différent, modifiez votre configuration Telegraf pour transférer les mesures vers le port personnalisé qui a été attribué à votre serveur InfluxDB.</p>
<p><code class="language-plaintext highlighter-rouge">[outputs.influxdb] when writing to [http://localhost:8086] : 401 Unauthorized: authorization failed</code><br />
<strong>Solution possible</strong> : assurez-vous que les informations didentification sont correctement définies dans votre configuration Telegraf. Assurez-vous également que vous avez créé un compte pour Telegraf sur votre serveur InfluxDB.</p>
<p><code class="language-plaintext highlighter-rouge">http: server gave HTTP response to HTTPS client</code><br />
<strong>Solution possible</strong> : assurez-vous que vous avez activé le paramètre dauthentification https dans le fichier de configuration InfluxDB. Il est réglé par défaut sur false.</p>
<p><code class="language-plaintext highlighter-rouge">x509: cannot validate certificate for 127.0.0.1 because it does not contain any IP SANs</code><br />
<strong>Solution possible</strong> : votre vérification TLS est activée, vous devez activer le paramètre insecure_skip_verify car lidentification du serveur ne peut pas être vérifiée pour les certificats auto-signés.</p>
<h2 id="monitorer-un-onduleur">Monitorer un onduleur</h2>
<ul>
<li><a href="https://technicalramblings.com/blog/monitoring-your-ups-stats-and-cost-with-influxdb-and-grafana-on-unraid-telegraf-edition/">Monitoring your UPS stats and cost with InfluxDB and Grafana on Unraid Telegraf Edition</a></li>
<li><a href="https://technicalramblings.com/blog/monitoring-your-ups-stats-and-cost-with-influxdb-and-grafana-on-unraid-2019-edition/">Monitoring your UPS stats and cost with InfluxDB and Grafana on Unraid Apcupsd Container Edition</a></li>
<li><a href="https://www.influxdata.com/integration/apcupsd/">Apcupsd Telegraf Plugin</a></li>
</ul>
<p>Recherche “dasboard” existant pour “APC UPS” (<a href="https://grafana.com/grafana/dashboards?search=apcups">https://grafana.com/grafana/dashboards?search=apcups</a>)<br />
<a href="https://grafana.com/grafana/dashboards/10835"><img src="/images/apc-ups-dashboard.png" alt="" /></a></p>
<p>Activer le plugin dentrée APCUPSD dans le télégramme et configurer le(s) serveur(s) de surveillance selon les besoins</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/telegraf/telegraf.d/apcupsd.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[[inputs.apcupsd]]
# # A list of running apcupsd server to connect to.
# # If not provided will default to tcp://127.0.0.1:3551
servers = ["tcp://192.168.0.46:3551"]
#
# ## Timeout for dialing server.
timeout = "10s"
</code></pre></div></div>
<p>Relancer le service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart telegraf
</code></pre></div></div>
<p>Importer le dashboard ID 10835</p>
<p><img src="/images/apc-ups-dashboard-01.png" alt="" width="600" /><br />
<img src="/images/apc-ups-dashboard-02.png" alt="" width="300" /><br />
<img src="/images/apc-ups-dashboard-03.png" alt="" width="300" /></p>
<p><img src="/images/apc-ups-dashboard-04.png" alt="" width="600" /></p>
<h2 id="liens">Liens</h2>
<ul>
<li><a href="https://www.suse.com/c/fr/kvm-monitoring-avec-prometheus-et-grafana/">KVM Monitoring avec Prometheus et Grafana</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-grafana-on-ubuntu-20-04-fr">Comment installer et sécuriser Grafana sur Ubuntu 20.04</a></li>
<li><a href="https://grafana.com/grafana/dashboards">Dashboards Official &amp; community built dashboards</a></li>
</ul>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2020-09-28T00:00:00+02:00"><!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<!--
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2020/09/24/Serveur-Debian10-Carte-ASRock-QC5000M.html">Serveur Debian10</a></div><div class="next"><span>SUIVANT</span><a href="/2020/09/30/Samba-Partage-de-fichiers.html">Partage de fichiers hôte linux et invité windows avec Samba</a></div></div></div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
$(function() {
var $this ,$scroll;
var $articleContent = $('.js-article-content');
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
$scroll = $(scroll);
$articleContent.find('.highlight').each(function() {
$this = $(this);
$this.attr('data-lang', $this.find('code').attr('data-lang'));
});
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
$this = $(this);
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
});
$articleContent.on('click', '.anchor', function() {
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
});
});
});
})();
</script>
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
<!-- end custom main bottom snippet -->
</div>
</div></div></div></div>
</div><script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $body = $('body'), $window = $(window);
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
var activeCount = 0;
function modal(options) {
var $root = this, visible, onChange, hideWhenWindowScroll = false;
var scrollTop;
function setOptions(options) {
var _options = options || {};
visible = _options.initialVisible === undefined ? false : show;
onChange = _options.onChange;
hideWhenWindowScroll = _options.hideWhenWindowScroll;
}
function init() {
setState(visible);
}
function setState(isShow) {
if (isShow === visible) {
return;
}
visible = isShow;
if (visible) {
activeCount++;
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
$root.addClass('modal--show');
$pageMain.scrollTop(scrollTop);
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
$window.on('keyup', handleKeyup);
} else {
activeCount > 0 && activeCount--;
$root.removeClass('modal--show');
$window.scrollTop(scrollTop);
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
$window.off('keyup', handleKeyup);
}
onChange && onChange(visible);
}
function show() {
setState(true);
}
function hide() {
setState(false);
}
function handleKeyup(e) {
// Char Code: 27 ESC
if (e.which === 27) {
hide();
}
}
setOptions(options);
init();
return {
show: show,
hide: hide,
$el: $root
};
}
$.fn.modal = modal;
});
})();
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
(function () {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
// search panel
var search = (window.search || (window.search = {}));
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
true : window.useDefaultSearchBox ;
var $searchModal = $('.js-page-search-modal');
var $searchToggle = $('.js-search-toggle');
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
var modalVisible = false;
search.searchModal = searchModal;
var $searchBox = null;
var $searchInput = null;
var $searchClear = null;
function getModalVisible() {
return modalVisible;
}
search.getModalVisible = getModalVisible;
function handleModalChange(visible) {
modalVisible = visible;
if (visible) {
search.onShow && search.onShow();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
} else {
search.onShow && search.onHide();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
setTimeout(function() {
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
search.clear && search.clear();
window.pageAsideAffix && window.pageAsideAffix.refresh();
}, 400);
}
}
$searchToggle.on('click', function() {
modalVisible ? searchModal.hide() : searchModal.show();
});
// Char Code: 83 S, 191 /
$(window).on('keyup', function(e) {
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
modalVisible || searchModal.show();
}
});
if (useDefaultSearchBox) {
$searchBox = $('.js-search-box');
$searchInput = $searchBox.children('input');
$searchClear = $searchBox.children('.js-icon-clear');
search.getSearchInput = function() {
return $searchInput.get(0);
};
search.getVal = function() {
return $searchInput.val();
};
search.setVal = function(val) {
$searchInput.val(val);
};
$searchInput.on('focus', function() {
$(this).addClass('focus');
});
$searchInput.on('blur', function() {
$(this).removeClass('focus');
});
$searchInput.on('input', window.throttle(function() {
var val = $(this).val();
if (val === '' || typeof val !== 'string') {
search.clear && search.clear();
} else {
$searchBox.addClass('not-empty');
search.onInputNotEmpty && search.onInputNotEmpty(val);
}
}, 400));
$searchClear.on('click', function() {
$searchInput.val(''); $searchBox.removeClass('not-empty');
search.clear && search.clear();
});
}
});
})();
</script><div class="search search--dark">
<div class="main">
<div class="search__header">Recherche</div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div>
</div>
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
Annuler</button>
</div>
<div id="results-container" class="search-result js-search-result"></div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
noResultsText: '<p>Aucun résultat!</p>',
json: '/search.json',
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a>&nbsp;(Création {create})</li>'
})
</script>
</div></div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function scrollToAnchor(anchor, duration, callback) {
var $root = this;
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
callback && callback();
});
}
$.fn.scrollToAnchor = scrollToAnchor;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function affix(options) {
var $root = this, $window = $(window), $scrollTarget, $scroll,
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
hasInit = false, curState;
function setOptions(options) {
var _options = options || {};
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroll && (scroll = _options.scroll);
_options.disabled !== undefined && (disabled = _options.disabled);
$scrollTarget = $(scrollTarget);
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
$scroll = $(scroll);
}
function preCalc() {
top();
rootHeight = $root.outerHeight();
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
rootLeft = $root.offset().left;
}
function calc(needPreCalc) {
needPreCalc && preCalc();
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
rootBottomTop = scrollBottom - rootTop;
}
function top() {
if (curState !== 'top') {
$root.removeClass('fixed').css({
left: 0,
top: 0
});
curState = 'top';
}
}
function fixed() {
if (curState !== 'fixed') {
$root.addClass('fixed').css({
left: rootLeft + 'px',
top: 0
});
curState = 'fixed';
}
}
function bottom() {
if (curState !== 'bottom') {
$root.removeClass('fixed').css({
left: 0,
top: rootBottomTop + 'px'
});
curState = 'bottom';
}
}
function setState() {
var scrollTop = $scrollTarget.scrollTop();
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
fixed();
} else if (scrollTop < rootTop) {
top();
} else {
bottom();
}
}
function init() {
if(!hasInit) {
var interval, timeout;
calc(true); setState();
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState();
});
$window.on('resize', function() {
disabled || (calc(true), setState());
});
hasInit = true;
}
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions,
refresh: function() {
calc(true, { animation: false }); setState();
}
};
}
$.fn.affix = affix;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function toc(options) {
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
function setOptions(options) {
var _options = options || {};
_options.selectors && (selectors = _options.selectors);
_options.container && (container = _options.container);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroller && (scroller = _options.scroller);
_options.disabled !== undefined && (disabled = _options.disabled);
$headings = $(container).find(selectors).filter('[id]');
$scrollTarget = $(scrollTarget);
$scroller = $(scroller);
}
function calc() {
headingsPos = [];
$headings.each(function() {
headingsPos.push(Math.floor($(this).position().top));
});
}
function setState(element, disabled) {
var scrollTop = $scrollTarget.scrollTop(), i;
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
if (element) {
$activeCur = element;
} else {
for (i = 0; i < headingsPos.length; i++) {
if (scrollTop >= headingsPos[i]) {
$activeCur = $tocLi.eq(i);
} else {
$activeCur || ($activeCur = $tocLi.eq(i));
break;
}
}
}
$activeLast && $activeLast.removeClass('active');
($activeLast = $activeCur).addClass('active');
}
function render() {
if(!hasRendered) {
$root.append($tocUl);
$headings.each(function() {
var $this = $(this);
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
});
$tocLi = $tocUl.children('li');
$tocUl.on('click', 'a', function(e) {
e.preventDefault();
var $this = $(this);
scrolling = true;
setState($this.parent());
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
scrolling = false;
});
});
}
hasRendered = true;
}
function init() {
var interval, timeout;
if(!hasInit) {
render(); calc(); setState(null, scrolling);
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState(null, scrolling);
});
$window.on('resize', window.throttle(function() {
if (!disabled) {
render(); calc(); setState(null, scrolling);
}
}, 100));
}
hasInit = true;
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions
};
}
$.fn.toc = toc;
});
})();
/*(function () {
})();*/
</script><script>
/* toc must before affix, since affix need to konw toc' height. */(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window);
var $articleContent = $('.js-article-content');
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
var toc;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
function disabled() {
return $col2.css('display') === 'none' || !hasToc;
}
tocDisabled = disabled();
toc = $tocRoot.toc({
selectors: TOC_SELECTOR,
container: $articleContent,
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
tocDisabled = disabled();
toc && toc.setOptions({
disabled: tocDisabled
});
}, 100));
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window), $pageFooter = $('.js-page-footer');
var $pageAside = $('.js-page-aside');
var affix;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
affix = $pageAside.affix({
offsetBottom: $pageFooter.outerHeight(),
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
scroll: hasSidebar ? $('.js-page-main').children() : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
affix && affix.setOptions({
disabled: tocDisabled
});
}, 100));
window.pageAsideAffix = affix;
});
})();
</script><!---->
</div>
<script>(function () {
var $root = document.getElementsByClassName('root')[0];
if (window.hasEvent('touchstart')) {
$root.dataset.isTouch = true;
document.addEventListener('touchstart', function(){}, false);
}
})();
</script>
</body>
</html>