Skip to content
This repository was archived by the owner on Mar 12, 2020. It is now read-only.

Commit 63a0957

Browse files
authored
Merge pull request #192 from mtxr/feature/fix-logging
Use python core logging for logs
2 parents 0985d7f + 201356a commit 63a0957

File tree

6 files changed

+74
-88
lines changed

6 files changed

+74
-88
lines changed

SQLTools.py

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
import sys
44
import os
55
import re
6+
import logging
67

78
import sublime
89
from sublime_plugin import WindowCommand, EventListener, TextCommand
910
from Default.paragraph import expand_to_paragraph
1011

1112
from .SQLToolsAPI import Utils
12-
from .SQLToolsAPI.Log import Log, Logger
1313
from .SQLToolsAPI.Storage import Storage, Settings
1414
from .SQLToolsAPI.Connection import Connection
1515
from .SQLToolsAPI.History import History
@@ -35,6 +35,19 @@
3535
connections = None
3636
history = None
3737

38+
# create pluggin logger
39+
DEFAULT_LOG_LEVEL = logging.WARNING
40+
plugin_logger = logging.getLogger(__package__)
41+
# some plugins are not playing by the rules and configure the root loger
42+
plugin_logger.propagate = False
43+
if not plugin_logger.handlers:
44+
plugin_logger_handler = logging.StreamHandler()
45+
plugin_logger_formatter = logging.Formatter("[{name}] {levelname}: {message}", style='{')
46+
plugin_logger_handler.setFormatter(plugin_logger_formatter)
47+
plugin_logger.addHandler(plugin_logger_handler)
48+
plugin_logger.setLevel(DEFAULT_LOG_LEVEL)
49+
logger = logging.getLogger(__name__)
50+
3851

3952
def getSublimeUserFolder():
4053
return os.path.join(sublime.packages_path(), 'User')
@@ -60,27 +73,30 @@ def startPlugin():
6073
try:
6174
settings = Settings(SETTINGS_FILENAME, default=SETTINGS_FILENAME_DEFAULT)
6275
except Exception as e:
63-
msg = __package__ + ": Failed to parse " + SQLTOOLS_SETTINGS_FILE + " file"
64-
print(msg + "\nError: " + str(e))
76+
msg = '{0}: Failed to parse {1} file'.format(__package__, SQLTOOLS_SETTINGS_FILE)
77+
logging.error(msg + "\nError: " + str(e))
6578
Window().status_message(msg)
6679

6780
try:
6881
connections = Settings(CONNECTIONS_FILENAME, default=CONNECTIONS_FILENAME_DEFAULT)
6982
except Exception as e:
70-
msg = __package__ + ": Failed to parse " + SQLTOOLS_CONNECTIONS_FILE + " file"
71-
print(msg + "\nError: " + str(e))
83+
msg = '{0}: Failed to parse {1} file'.format(__package__, SQLTOOLS_CONNECTIONS_FILE)
84+
logging.error(msg + "\nError: " + str(e))
7285
Window().status_message(msg)
7386

7487
queries = Storage(QUERIES_FILENAME, default=QUERIES_FILENAME_DEFAULT)
7588
history = History(settings.get('history_size', 100))
7689

77-
Logger.setPackageVersion(__version__)
78-
Logger.setPackageName(__package__)
79-
Logger.setLogging(settings.get('debug', True))
90+
if settings.get('debug', False):
91+
plugin_logger.setLevel(logging.DEBUG)
92+
else:
93+
plugin_logger.setLevel(DEFAULT_LOG_LEVEL)
94+
8095
Connection.setTimeout(settings.get('thread_timeout', 15))
8196
Connection.setHistoryManager(history)
8297

83-
Log(__package__ + " Loaded!")
98+
logger.info('plugin (re)loaded')
99+
logger.info('version %s', __version__)
84100

85101

86102
def getConnections():
@@ -122,7 +138,6 @@ def loadDefaultConnection():
122138
default = connections.get('default', False)
123139
if not default:
124140
return
125-
Log('Default database set to ' + default + '. Loading options and auto complete.')
126141
return default
127142

128143

@@ -308,11 +323,15 @@ def checkDefaultConnection():
308323
default = loadDefaultConnection()
309324
if not default:
310325
return
326+
327+
logger.info('default connection is set to "%s"', default)
328+
311329
try:
312-
ST.conn = ST.connectionList.get(default)
330+
ST.conn = ST.connectionList[default]
331+
except KeyError as e:
332+
logger.error('connection "%s" set as default, but it does not exists', default)
333+
else:
313334
ST.loadConnectionData()
314-
except Exception:
315-
Log("Invalid connection setted")
316335

317336
@staticmethod
318337
def loadConnectionData(tablesCallback=None, columnsCallback=None, functionsCallback=None):
@@ -372,7 +391,7 @@ def setConnection(index, tablesCallback=None, columnsCallback=None, functionsCal
372391
connListNames.sort()
373392
ST.conn = ST.connectionList.get(connListNames[index])
374393
ST.loadConnectionData(tablesCallback, columnsCallback, functionsCallback)
375-
Log('Connection {0} selected'.format(ST.conn))
394+
logger.info('Connection "{0}" selected'.format(ST.conn))
376395

377396
@staticmethod
378397
def selectConnection(tablesCallback=None, columnsCallback=None, functionsCallback=None):
@@ -452,7 +471,7 @@ def on_query_completions(view, prefix, locations):
452471
lineStr = view.substr(lineStartToLocation)
453472
prefix = re.split('[^`\"\w.\$]+', lineStr).pop()
454473
except Exception as e:
455-
Log(e)
474+
logger.debug(e)
456475

457476
# use current paragraph as sql text to parse
458477
sqlRegion = expand_to_paragraph(view, currentPoint)
@@ -732,7 +751,6 @@ def reload():
732751
imp.reload(sys.modules[__package__ + ".SQLToolsAPI.Completion"])
733752
imp.reload(sys.modules[__package__ + ".SQLToolsAPI.Storage"])
734753
imp.reload(sys.modules[__package__ + ".SQLToolsAPI.History"])
735-
imp.reload(sys.modules[__package__ + ".SQLToolsAPI.Log"])
736754
imp.reload(sys.modules[__package__ + ".SQLToolsAPI.Command"])
737755
imp.reload(sys.modules[__package__ + ".SQLToolsAPI.Connection"])
738756
except Exception as e:
@@ -760,9 +778,9 @@ def plugin_loaded():
760778
from package_control import events
761779

762780
if events.install(__name__):
763-
Log('Installed %s!' % events.install(__name__))
781+
logger.info('Installed %s!' % events.install(__name__))
764782
elif events.post_upgrade(__name__):
765-
Log('Upgraded to %s!' % events.post_upgrade(__name__))
783+
logger.info('Upgraded to %s!' % events.post_upgrade(__name__))
766784
sublime.message_dialog(('{0} was upgraded.' +
767785
'If you have any problem,' +
768786
'just restart your Sublime Text.'
@@ -774,3 +792,8 @@ def plugin_loaded():
774792

775793
startPlugin()
776794
reload()
795+
796+
797+
def plugin_unloaded():
798+
if plugin_logger.handlers:
799+
plugin_logger.handlers.pop()

SQLToolsAPI/Command.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
import signal
33
import subprocess
44
import time
5+
import logging
56

67
from threading import Thread, Timer
7-
from .Log import Log
88

9+
logger = logging.getLogger(__name__)
910

1011
class Command(object):
1112
timeout = 15
@@ -175,8 +176,9 @@ def stop(self):
175176
os.kill(self.process.pid, sig)
176177
self.process = None
177178

178-
Log("Your command is taking too long to run. Process killed")
179-
self.callback("Command execution time exceeded 'thread_timeout'.\nProcess killed!\n\n")
179+
logger.info("command execution exceeded timeout (%s s), process killed", self.timeout)
180+
self.callback("Command execution time exceeded 'thread_timeout' ({0} s).\nProcess killed!\n\n"
181+
.format(self.timeout))
180182
except Exception:
181183
pass
182184

SQLToolsAPI/Completion.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import re
2+
import logging
23
from collections import namedtuple
34

45
from .ParseUtils import extractTables
56

6-
_join_cond_regex_pattern = r"\s+?JOIN\s+?[\w\.`\"]+\s+?(?:AS\s+)?(\w+)\s+?ON\s+?(?:[\w\.]+)?$"
7-
JOIN_COND_REGEX = re.compile(_join_cond_regex_pattern, re.IGNORECASE)
7+
JOIN_COND_PATTERN = r"\s+?JOIN\s+?[\w\.`\"]+\s+?(?:AS\s+)?(\w+)\s+?ON\s+?(?:[\w\.]+)?$"
8+
JOIN_COND_REGEX = re.compile(JOIN_COND_PATTERN, re.IGNORECASE)
89

910
keywords_list = [
1011
'SELECT', 'UPDATE', 'DELETE', 'INSERT', 'INTO', 'FROM',
@@ -13,6 +14,8 @@
1314
'LIMIT', 'DISTINCT', 'SET'
1415
]
1516

17+
logger = logging.getLogger(__name__)
18+
1619

1720
# this function is generously used in completions code to get rid
1821
# of all sorts of leading and trailing quotes in RDBMS identifiers
@@ -28,7 +31,7 @@ def _stripQuotesOnDemand(ident, doStrip=True):
2831

2932

3033
def _startsWithQuote(ident):
31-
# str.startswith can be matched against a tuple
34+
# ident is matched against any of the possible ident quotes
3235
quotes = ('`', '"')
3336
return ident.startswith(quotes)
3437

@@ -45,24 +48,23 @@ def _escapeDollarSign(ident):
4548

4649

4750
class CompletionItem(namedtuple('CompletionItem', ['type', 'ident'])):
48-
"""
49-
Represents a potential or actual completion item.
50-
* type - Type of item e.g. (Table, Function, Column)
51-
* ident - identifier e.g. ("tablename.column", "database.table", "alias")
51+
"""Represents a potential or actual completion item.
52+
* type - type of item (Table, Function, Column)
53+
* ident - identifier (table.column, schema.table, alias)
5254
"""
5355
__slots__ = ()
5456

55-
# parent of identifier, e.g. "table" from "table.column"
5657
@property
5758
def parent(self):
59+
"""Parent of identifier, e.g. "table" from "table.column" """
5860
if self.ident.count('.') == 0:
5961
return None
6062
else:
6163
return self.ident.partition('.')[0]
6264

63-
# name of identifier, e.g. "column" from "table.column"
6465
@property
6566
def name(self):
67+
"""Name of identifier, e.g. "column" from "table.column" """
6668
return self.ident.split('.').pop()
6769

6870
# for functions - strip open bracket "(" and everything after that
@@ -281,7 +283,8 @@ def _getAutoCompleteListSmart(self, prefix, sql, sqlToCursor):
281283
try:
282284
identifiers = extractTables(sql)
283285
except Exception as e:
284-
print(e)
286+
logger.debug('Failed to extact the list identifiers from SQL:\n {}'.format(sql),
287+
exc_info=True)
285288

286289
# joinAlias is set only if user is editing join condition with alias. E.g.
287290
# SELECT a.* from tbl_a a inner join tbl_b b ON |
@@ -292,7 +295,8 @@ def _getAutoCompleteListSmart(self, prefix, sql, sqlToCursor):
292295
if joinCondMatch:
293296
joinAlias = joinCondMatch.group(1)
294297
except Exception as e:
295-
print(e)
298+
logger.debug('Failed search of join condition, SQL:\n {}'.format(sqlToCursor),
299+
exc_info=True)
296300

297301
autocompleteList = []
298302
inhibit = False

SQLToolsAPI/Connection.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import shutil
22
import shlex
33
import codecs
4+
import logging
45
import sqlparse
56

6-
from .Log import Log
77
from . import Utils as U
88
from . import Command as C
99

10+
logger = logging.getLogger(__name__)
11+
1012

1113
def _encoding_exists(enc):
1214
try:
@@ -17,8 +19,8 @@ def _encoding_exists(enc):
1719

1820

1921
class Connection(object):
20-
DB_CLI_NOT_FOUND_MESSAGE = """'{0}' could not be found.
21-
Please set the path to '{0}' binary in your SQLTools settings before continuing.
22+
DB_CLI_NOT_FOUND_MESSAGE = """DB CLI '{0}' could not be found.
23+
Please set the path to DB CLI '{0}' binary in your SQLTools settings before continuing.
2224
Example of "cli" section in SQLTools.sublime-settings:
2325
/* ... (note the use of forward slashes) */
2426
"cli" : {{
@@ -72,7 +74,7 @@ def __init__(self, name, options, settings=None, commandClass='ThreadCommand'):
7274

7375
cli_path = shutil.which(self.cli)
7476
if cli_path is None:
75-
Log(self.DB_CLI_NOT_FOUND_MESSAGE.format(self.cli))
77+
logger.info(self.DB_CLI_NOT_FOUND_MESSAGE.format(self.cli))
7678
raise FileNotFoundError(self.DB_CLI_NOT_FOUND_MESSAGE.format(self.cli))
7779

7880
def __str__(self):
@@ -207,7 +209,7 @@ def execute(self, queries, callback, stream=None):
207209
args = self.buildArgs(queryName)
208210
env = self.buildEnv()
209211

210-
Log("Query: " + str(queryToRun))
212+
logger.debug("Query: %s", str(queryToRun))
211213

212214
self.Command.createAndRun(args=args,
213215
env=env,
@@ -297,7 +299,7 @@ def buildArgs(self, queryName=None):
297299
mainArgs = mainArgs.format(**self.options)
298300
args = args + shlex.split(mainArgs)
299301

300-
Log('Using cli args ' + ' '.join(args))
302+
logger.debug('CLI args (%s): %s', str(queryName), ' '.join(args))
301303
return args
302304

303305
def buildEnv(self):
@@ -322,7 +324,7 @@ def buildEnv(self):
322324
if formattedValue:
323325
env.update({var: formattedValue})
324326

325-
Log('Environment for command: ' + str(env))
327+
logger.debug('CLI environment: %s', str(env))
326328
return env
327329

328330
def getOptionsForSgdbCli(self):
@@ -342,9 +344,10 @@ def formatOptionalArgument(argument, formatOptions):
342344
@staticmethod
343345
def setTimeout(timeout):
344346
Connection.timeout = timeout
345-
Log('Connection timeout set to {0} seconds'.format(timeout))
347+
logger.info('Connection timeout set to {0} seconds'.format(timeout))
346348

347349
@staticmethod
348350
def setHistoryManager(manager):
349351
Connection.history = manager
350-
Log('Connection history defined with max size {0}'.format(manager.getMaxSize()))
352+
size = manager.getMaxSize()
353+
logger.info('Connection history size is {0}'.format(size))

SQLToolsAPI/Log.py

Lines changed: 0 additions & 45 deletions
This file was deleted.

SQLToolsAPI/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
__version__ = "v0.2.5"
1+
__version__ = "v0.3.0"
22

33

44
__all__ = [
5-
'Log',
65
'Utils',
76
'Completion',
87
'Command',

0 commit comments

Comments
 (0)