-
Notifications
You must be signed in to change notification settings - Fork 388
Expand file tree
/
Copy pathenvironment.py
More file actions
148 lines (117 loc) · 5.31 KB
/
Copy pathenvironment.py
File metadata and controls
148 lines (117 loc) · 5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# Copyright © 2011-2026 Splunk, Inc.
#
# 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.
import sys
from logging import StreamHandler, getLogger, root
from logging.config import fileConfig
from os import chdir, environ, getcwd, path
def configure_logging(logger_name, filename=None):
"""Configure logging and return the named logger and the location of the logging configuration file loaded.
This function expects a Splunk app directory structure::
<app-root>
bin
...
default
...
local
...
This function looks for a logging configuration file at each of these locations, loading the first, if any,
logging configuration file that it finds::
local / {name}.logging.conf
default / {name}.logging.conf
local / logging.conf
default / logging.conf
The current working directory is set to *<app-root>* before the logging configuration file is loaded. Hence, paths
in the logging configuration file are relative to *<app-root>*. The current directory is reset before return.
You may short circuit the search for a logging configuration file by providing an alternative file location in
`path`. Logging configuration files must be in `ConfigParser format`_.
#Arguments:
:param logger_name: Logger name
:type logger_name: bytes, unicode
:param filename: Location of an alternative logging configuration file or `None`.
:type filename: bytes, unicode or NoneType
:returns: The named logger and the location of the logging configuration file loaded.
:rtype: tuple
.. _ConfigParser format: https://docs.python.org/2/library/logging.config.html#configuration-file-format
"""
if filename is None:
if logger_name is None:
probing_paths = [
path.join("local", "logging.conf"),
path.join("default", "logging.conf"),
]
else:
probing_paths = [
path.join("local", logger_name + ".logging.conf"),
path.join("default", logger_name + ".logging.conf"),
path.join("local", "logging.conf"),
path.join("default", "logging.conf"),
]
for relative_path in probing_paths:
configuration_file = path.join(app_root, relative_path)
if path.exists(configuration_file):
filename = configuration_file
break
elif not path.isabs(filename):
found = False
for conf in "local", "default":
configuration_file = path.join(app_root, conf, filename)
if path.exists(configuration_file):
filename = configuration_file
found = True
break
if not found:
raise ValueError(
f'Logging configuration file "{filename}" not found in local or default directory'
)
elif not path.exists(filename):
raise ValueError(f'Logging configuration file "{filename}" not found')
if filename is not None:
global _current_logging_configuration_file
filename = path.realpath(filename)
app_root_real = path.realpath(app_root)
if path.commonpath([filename, app_root_real]) != app_root_real: # pyright: ignore[reportUnknownArgumentType]
raise ValueError(
f'Logging configuration file "{filename}" is outside the app directory'
)
if filename != _current_logging_configuration_file:
working_directory = getcwd()
chdir(app_root)
try:
fileConfig(filename, {"SPLUNK_HOME": splunk_home})
finally:
chdir(working_directory)
_current_logging_configuration_file = filename
if len(root.handlers) == 0:
root.addHandler(StreamHandler())
return None if logger_name is None else getLogger(logger_name), filename
_current_logging_configuration_file = None
def _find_app_root(app_file: str, splunk_home: str) -> str:
"""Return the app root directory for a search command script."""
splunk_apps_dir = path.join(splunk_home, "etc", "apps")
app_relpath = path.relpath(path.abspath(app_file), splunk_apps_dir)
app_dir = app_relpath.split(path.sep, 1)[0]
if app_dir == path.pardir: # app_file not in $SPLUNK_HOME/etc/apps
return path.dirname(path.abspath(path.dirname(app_file)))
return path.join(splunk_apps_dir, app_dir)
splunk_home = path.abspath(path.join(getcwd(), environ.get("SPLUNK_HOME", "")))
app_file = getattr(sys.modules["__main__"], "__file__", sys.executable)
app_root = _find_app_root(app_file, splunk_home)
splunklib_logger, logging_configuration = configure_logging("splunklib")
__all__ = [
"app_file",
"app_root",
"logging_configuration",
"splunk_home",
"splunklib_logger",
]