Feature: logging level and disabling plugins (#5)

- Add logging level configuration item
- Add plugin disabling mechanism
- Some trivial chores
diff --git a/Makefile b/Makefile
index 56f4369..3d4947d 100644
--- a/Makefile
+++ b/Makefile
@@ -19,10 +19,9 @@
 setup:
 	python3 -m pip install --upgrade pip
 	python3 -m pip install grpcio --ignore-installed
-	python3 -m pip install grpcio-tools
-	python3 -m pip install flake8
 
 gen:
+	python3 -m grpc_tools.protoc --version || python3 -m pip install grpcio-tools
 	python3 -m grpc_tools.protoc -I protocol --python_out=. --grpc_python_out=. protocol/**/*.proto
 	touch browser/__init__.py
 	touch common/__init__.py
@@ -32,6 +31,7 @@
 	touch service_mesh_probe/__init__.py
 
 lint: clean
+	flake8 --version || python3 -m pip install flake8
 	flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
 	flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
 
@@ -44,6 +44,9 @@
 install: gen
 	python3 setup.py install --force
 
+package: clean gen
+	python3 setup.py sdist bdist_wheel
+
 clean:
 	rm -rf browser common language_agent management profile service_mesh_probe
 	rm -rf skywalking_python.egg-info dist build
diff --git a/README.md b/README.md
index 2d036bc..c45e0c1 100644
--- a/README.md
+++ b/README.md
@@ -30,19 +30,21 @@
 
 Environment Variable | Description | Default
 | :--- | :--- | :--- |
-| `SW_AGENT_NAME` | The name of the Python service | `Python Service Name` 
-| `SW_AGENT_INSTANCE` | The name of the Python service instance | Randomly generated
-| `SW_AGENT_COLLECTOR_BACKEND_SERVICES` | The backend OAP server address | `127.0.0.1:11800`
-| `SW_AGENT_PROTOCOL` | The protocol to communicate with the backend OAP, currently only `grpc` is supported | `grpc`
-| `SW_LOGGING_LEVEL` | The logging level | `INFO` |
+| `SW_AGENT_NAME` | The name of the Python service | `Python Service Name` |
+| `SW_AGENT_INSTANCE` | The name of the Python service instance | Randomly generated |
+| `SW_AGENT_COLLECTOR_BACKEND_SERVICES` | The backend OAP server address | `127.0.0.1:11800` |
+| `SW_AGENT_PROTOCOL` | The protocol to communicate with the backend OAP, currently only `grpc` is supported | `grpc` |
+| `SW_AGENT_LOGGING_LEVEL` | The logging level, could be one of `CRITICAL`, `FATAL`, `ERROR`, `WARN`(`WARNING`), `INFO`, `DEBUG` | `INFO` |
+| `SW_AGENT_DISABLE_PLUGINS` | The name patterns in CSV pattern, plugins whose name matches one of the pattern won't be installed | `''` |
 
 ## Supported Libraries
 
 There're some built-in plugins that support automatic instrumentation of Python libraries, the complete lists are as follow:
 
-- Http
-  - [http.server](https://docs.python.org/3/library/http.server.html)
-  - [urllib.request](https://docs.python.org/3/library/urllib.request.html)
+Library | Plugin Name
+| :--- | :--- |
+| [http.server](https://docs.python.org/3/library/http.server.html) | `sw_http_server` |
+| [urllib.request](https://docs.python.org/3/library/urllib.request.html) | `sw_urllib_request` |
 
 ## API
 
@@ -96,5 +98,9 @@
     some_method()
 ```
 
+## FAQs
+
+Check [the FAQ page](docs/FAQ.md) or add the FAQs there.
+
 ## License
 Apache 2.0
diff --git a/docs/FAQ.md b/docs/FAQ.md
new file mode 100644
index 0000000..55e7b0c
--- /dev/null
+++ b/docs/FAQ.md
@@ -0,0 +1,12 @@
+## FAQ
+
+Q: How to disable some plugins?
+A: You can find the plugin name in [the list](../README.md#supported-libraries) and disable one or more plugins by following methods.
+
+```python
+from skywalking import config
+
+config.disable_plugins = ['sw_http_server', 'sw_urllib_request']  # can be also CSV format, i.e. 'sw_http_server,sw_urllib_request'
+```
+
+you can also disable the plugins via environment variables `SW_AGENT_DISABLE_PLUGINS`.
diff --git a/setup.py b/setup.py
index 0370c9d..958886d 100644
--- a/setup.py
+++ b/setup.py
@@ -35,5 +35,7 @@
     license="Apache 2.0",
     packages=find_packages(exclude=("tests",)),
     include_package_data=True,
-    install_requires=[],
+    install_requires=[
+        "grpcio",
+    ],
 )
diff --git a/skywalking/__init__.py b/skywalking/__init__.py
index 8848423..1dd5b45 100644
--- a/skywalking/__init__.py
+++ b/skywalking/__init__.py
@@ -20,10 +20,6 @@
 from enum import Enum
 from typing import List
 
-from skywalking import loggings
-
-loggings.init()
-
 
 class Component(Enum):
     Unknown = 0
diff --git a/skywalking/agent/__init__.py b/skywalking/agent/__init__.py
index ce410ad..2271665 100644
--- a/skywalking/agent/__init__.py
+++ b/skywalking/agent/__init__.py
@@ -69,6 +69,8 @@
     global __started
     if __started:
         raise RuntimeError('the agent can only be started once')
+    from skywalking import loggings
+    loggings.init()
     __started = True
     __init()
     __heartbeat_thread.start()
diff --git a/skywalking/config/__init__.py b/skywalking/config/__init__.py
index 6fd2823..ffd3fd0 100644
--- a/skywalking/config/__init__.py
+++ b/skywalking/config/__init__.py
@@ -17,12 +17,15 @@
 
 import os
 import uuid
+from typing import List
 
 service_name = os.getenv('SW_AGENT_NAME') or 'Python Service Name'  # type: str
 service_instance = os.getenv('SW_AGENT_INSTANCE') or str(uuid.uuid1()).replace('-', '')  # type: str
 collector_address = os.getenv('SW_AGENT_COLLECTOR_BACKEND_SERVICES') or '127.0.0.1:11800'  # type: str
 protocol = os.getenv('SW_AGENT_PROTOCOL') or 'grpc'  # type: str
-authentication = os.getenv('SW_AGENT_AUTHENTICATION')
+authentication = os.getenv('SW_AGENT_AUTHENTICATION')  # type: str
+logging_level = os.getenv('SW_AGENT_LOGGING_LEVEL') or 'INFO'  # type: str
+disable_plugins = (os.getenv('SW_AGENT_DISABLE_PLUGINS') or '').split(',')  # type: List[str]
 
 
 def init(
diff --git a/skywalking/loggings/__init__.py b/skywalking/loggings/__init__.py
index 1ba3646..35fc16d 100644
--- a/skywalking/loggings/__init__.py
+++ b/skywalking/loggings/__init__.py
@@ -16,13 +16,12 @@
 #
 
 import logging
-import os
 
-__logging_lever = (os.getenv('SW_LOGGING_LEVEL') or 'INFO').upper()
+from skywalking import config
 
 
 def init():
     logging.basicConfig(
-        level=logging.getLevelName(__logging_lever),
+        level=logging.getLevelName(config.logging_level),
         format='%(name)-32s [%(threadName)-15s] [%(levelname)-8s] %(message)s',
     )
diff --git a/skywalking/plugins/__init__.py b/skywalking/plugins/__init__.py
index d22d1bc..3995f1d 100644
--- a/skywalking/plugins/__init__.py
+++ b/skywalking/plugins/__init__.py
@@ -17,6 +17,9 @@
 import inspect
 import logging
 import pkgutil
+import re
+
+from skywalking import config
 
 import skywalking
 
@@ -25,6 +28,14 @@
 
 def install():
     for importer, modname, ispkg in pkgutil.iter_modules(skywalking.plugins.__path__):
+        disable_patterns = config.disable_plugins
+        if isinstance(disable_patterns, str):
+            disable_patterns = [re.compile(p.strip()) for p in disable_patterns.split(',') if p.strip()]
+        else:
+            disable_patterns = [re.compile(p.strip()) for p in disable_patterns if p.strip()]
+        if any(pattern.match(modname) for pattern in disable_patterns):
+            logger.info('plugin %s is disabled and thus won\'t be installed', modname)
+            continue
         logger.debug('installing plugin %s', modname)
         plugin = importer.find_module(modname).load_module(modname)
         if not hasattr(plugin, 'install') or inspect.ismethod(getattr(plugin, 'install')):
diff --git a/skywalking/plugins/sw_http/__init__.py b/skywalking/plugins/sw_http_server/__init__.py
similarity index 100%
rename from skywalking/plugins/sw_http/__init__.py
rename to skywalking/plugins/sw_http_server/__init__.py
diff --git a/skywalking/plugins/sw_request/__init__.py b/skywalking/plugins/sw_urllib_request/__init__.py
similarity index 100%
rename from skywalking/plugins/sw_request/__init__.py
rename to skywalking/plugins/sw_urllib_request/__init__.py
diff --git a/tests/consumer.py b/tests/consumer.py
index a40c1b6..d874f6c 100644
--- a/tests/consumer.py
+++ b/tests/consumer.py
@@ -15,23 +15,27 @@
 # limitations under the License.
 #
 
+import os
 from urllib import request
 
 from skywalking import agent, config
 
 if __name__ == '__main__':
     config.service_name = 'consumer'
+    config.logging_level = 'DEBUG'
     agent.start()
 
     import socketserver
     from http.server import BaseHTTPRequestHandler
 
+    provider_url = os.getenv('PROVIDER_URL') or 'http://localhost:9091/'
+
     class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
 
         def do_GET(self):
             self.send_response(200)
             self.end_headers()
-            req = request.Request('http://localhost:9091/whatever')
+            req = request.Request(provider_url + '/whatever')
             with request.urlopen(req) as res:
                 self.wfile.write(res.read(300))
 
diff --git a/tests/provider.py b/tests/provider.py
index c13eca0..afa7bb7 100644
--- a/tests/provider.py
+++ b/tests/provider.py
@@ -21,6 +21,7 @@
 
 if __name__ == '__main__':
     config.service_name = 'provider'
+    config.logging_level = 'DEBUG'
     agent.start()
 
     import socketserver