forked from 418sec/postgresql-metrics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommon.py
118 lines (100 loc) · 4.68 KB
/
common.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module defines some basic common application functionality, like logging.
"""
import os
import logbook
import yaml
def get_logger(logger_name="postgresql-metrics"):
return logbook.Logger(logger_name)
def figure_out_log_level(given_level):
if isinstance(given_level, str):
return logbook.lookup_level(given_level.strip().upper())
else:
return given_level
def init_logging_stderr(log_level='notset', bubble=False):
handler = logbook.StderrHandler(level=figure_out_log_level(log_level), bubble=bubble)
handler.push_application()
get_logger().debug("stderr logging initialized")
def init_logging_file(filename, log_level='notset', rotate_log=True, rotate_max_size=10485760,
bubble=True):
log_dir = os.path.dirname(filename)
if not os.path.exists(log_dir):
os.makedirs(log_dir)
if rotate_log is True:
handler = logbook.RotatingFileHandler(filename, level=figure_out_log_level(log_level),
max_size=int(rotate_max_size), bubble=bubble)
else:
handler = logbook.FileHandler(filename, level=figure_out_log_level(log_level),
bubble=bubble)
handler.push_application()
get_logger().debug("file based logging initialized in directory: " + log_dir)
def init_logging_syslog(log_level='notset', facility='local0', bubble=True):
handler = logbook.SyslogHandler('postgresql-metrics', facility=facility,
level=figure_out_log_level(log_level), bubble=bubble)
handler.push_application()
get_logger().debug("syslog logging initialized")
def merge_configs(to_be_merged, default):
"""Merges two configuration dictionaries by overwriting values with
same keys, with the priority on values given on the 'left' side, so
the to_be_merged dict.
Notice that with lists in the configuration, it skips from the default
(right side) the tuples in that which already exist in the left side
to_be_merged list. This is used to be able to override time intervals for
default values in the configuration.
Example:
In [1]: x = [["get_stats_disk_usage_for_database", 180],
["get_stats_tx_rate_for_database", 500]]
In [2]: y = [["get_stats_seconds_since_last_vacuum_per_table", 60],
["get_stats_tx_rate_for_database", 60]]
In [3]: merge_configs(x, y)
Out[3]:
[['get_stats_disk_usage_for_database', 180],
['get_stats_tx_rate_for_database', 500],
['get_stats_seconds_since_last_vacuum_per_table', 60]]
"""
if isinstance(to_be_merged, dict) and isinstance(default, dict):
for k, v in default.items():
if k not in to_be_merged:
to_be_merged[k] = v
else:
to_be_merged[k] = merge_configs(to_be_merged[k], v)
elif isinstance(to_be_merged, list) and isinstance(default, list):
same_keys = set()
for x in to_be_merged:
for y in default:
if isinstance(x, (list, set, tuple)) and isinstance(y, (list, set, tuple)) and len(
x) > 0 and len(y) > 0 and x[0] == y[0]:
same_keys.add(x[0])
for y in default:
if not isinstance(y, (list, set, tuple)) or y[0] not in same_keys:
to_be_merged.append(y)
return to_be_merged
def find_and_parse_config(config_path):
"""Finds the service configuration file and parses it.
Checks also a directory called default, to check for default configuration values,
that will be overwritten by the actual configuration found on given path.
"""
config_filename = os.path.basename(config_path)
config_root = os.path.dirname(config_path)
default_root = os.path.join(config_root, 'default')
config_dict = {}
for config_dir in (default_root, config_root):
current_path = os.path.join(config_dir, config_filename)
if os.path.isfile(current_path):
with open(current_path, 'r') as f:
read_config_dict = yaml.safe_load(f)
config_dict = merge_configs(read_config_dict, config_dict)
return config_dict