Skip to content

Commit 68cfeb0

Browse files
committed
Python: Model logging from the logging module
1 parent c05e375 commit 68cfeb0

File tree

2 files changed

+81
-24
lines changed

2 files changed

+81
-24
lines changed

python/ql/src/semmle/python/frameworks/Stdlib.qll

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,63 @@ private module Stdlib {
12551255
result = this.getArgByName("string")
12561256
}
12571257
}
1258+
1259+
// ---------------------------------------------------------------------------
1260+
// logging
1261+
// ---------------------------------------------------------------------------
1262+
/**
1263+
* Provides models for the `logging.Logger` class and subclasses.
1264+
*
1265+
* See https://docs.python.org/3.9/library/logging.html#logging.Logger.
1266+
*/
1267+
module Logger {
1268+
/** Gets a reference to the `logging.Logger` class or any subclass. */
1269+
API::Node subclassRef() {
1270+
result = API::moduleImport("logging").getMember("Logger").getASubclass*()
1271+
}
1272+
1273+
/** Gets a reference to an instance of `logging.Logger` or any subclass. */
1274+
API::Node instance() {
1275+
result = subclassRef().getReturn()
1276+
or
1277+
result = API::moduleImport("logging").getMember("root")
1278+
or
1279+
result = API::moduleImport("logging").getMember("getLogger").getReturn()
1280+
}
1281+
}
1282+
1283+
/**
1284+
* A call to one of the logging methods from `logging` or on a `logging.Logger`
1285+
* subclass.
1286+
*
1287+
* See:
1288+
* - https://docs.python.org/3.9/library/logging.html#logging.debug
1289+
* - https://docs.python.org/3.9/library/logging.html#logging.Logger.debug
1290+
*/
1291+
class LoggerLogCall extends Logging::Range, DataFlow::CallCfgNode {
1292+
/** The argument-index where the message is passed. */
1293+
int msgIndex;
1294+
1295+
LoggerLogCall() {
1296+
exists(string method |
1297+
method in ["critical", "fatal", "error", "warning", "warn", "info", "debug", "exception"] and
1298+
msgIndex = 0
1299+
or
1300+
method = "log" and
1301+
msgIndex = 1
1302+
|
1303+
this = Logger::instance().getMember(method).getACall()
1304+
or
1305+
this = API::moduleImport("logging").getMember(method).getACall()
1306+
)
1307+
}
1308+
1309+
override DataFlow::Node getAnInput() {
1310+
result = this.getArgByName("msg")
1311+
or
1312+
result = this.getArg(any(int i | i >= msgIndex))
1313+
}
1314+
}
12581315
}
12591316

12601317
// ---------------------------------------------------------------------------

python/ql/test/library-tests/frameworks/stdlib/Logging.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,38 @@
88

99
LOGGER = logging.getLogger("LOGGER")
1010

11-
logging.info(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
12-
logging.info(msg="hello") # $ MISSING: loggingInput="hello"
11+
logging.info(msg, password) # $ loggingInput=msg loggingInput=password
12+
logging.info(msg="hello") # $ loggingInput="hello"
1313

14-
logging.log(logging.INFO, msg, password) # $ MISSING: loggingInput=msg loggingInput=password
15-
LOGGER.log(logging.INFO, msg, password) # $ MISSING: loggingInput=msg loggingInput=password
14+
logging.log(logging.INFO, msg, password) # $ loggingInput=msg loggingInput=password
15+
LOGGER.log(logging.INFO, msg, password) # $ loggingInput=msg loggingInput=password
1616

17-
logging.root.info(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
17+
logging.root.info(msg, password) # $ loggingInput=msg loggingInput=password
1818

1919
# test of all levels
2020

21-
logging.critical(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
22-
logging.fatal(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
23-
logging.error(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
24-
logging.warning(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
25-
logging.warn(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
26-
logging.info(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
27-
logging.debug(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
28-
logging.exception(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
29-
30-
LOGGER.critical(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
31-
LOGGER.fatal(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
32-
LOGGER.error(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
33-
LOGGER.warning(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
34-
LOGGER.warn(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
35-
LOGGER.info(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
36-
LOGGER.debug(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
37-
LOGGER.exception(msg, password) # $ MISSING: loggingInput=msg loggingInput=password
21+
logging.critical(msg, password) # $ loggingInput=msg loggingInput=password
22+
logging.fatal(msg, password) # $ loggingInput=msg loggingInput=password
23+
logging.error(msg, password) # $ loggingInput=msg loggingInput=password
24+
logging.warning(msg, password) # $ loggingInput=msg loggingInput=password
25+
logging.warn(msg, password) # $ loggingInput=msg loggingInput=password
26+
logging.info(msg, password) # $ loggingInput=msg loggingInput=password
27+
logging.debug(msg, password) # $ loggingInput=msg loggingInput=password
28+
logging.exception(msg, password) # $ loggingInput=msg loggingInput=password
29+
30+
LOGGER.critical(msg, password) # $ loggingInput=msg loggingInput=password
31+
LOGGER.fatal(msg, password) # $ loggingInput=msg loggingInput=password
32+
LOGGER.error(msg, password) # $ loggingInput=msg loggingInput=password
33+
LOGGER.warning(msg, password) # $ loggingInput=msg loggingInput=password
34+
LOGGER.warn(msg, password) # $ loggingInput=msg loggingInput=password
35+
LOGGER.info(msg, password) # $ loggingInput=msg loggingInput=password
36+
LOGGER.debug(msg, password) # $ loggingInput=msg loggingInput=password
37+
LOGGER.exception(msg, password) # $ loggingInput=msg loggingInput=password
3838

3939
# not sure how to make these print anything, but just to show that it works
40-
logging.Logger("foo").info("hello") # $ MISSING: loggingInput="hello"
40+
logging.Logger("foo").info("hello") # $ loggingInput="hello"
4141

4242
class MyLogger(logging.Logger):
4343
pass
4444

45-
MyLogger("bar").info("hello") # $ MISSING: loggingInput="hello"
45+
MyLogger("bar").info("hello") # $ loggingInput="hello"

0 commit comments

Comments
 (0)