fix tox setup for snmptrap

Change-Id: I39adcd37cab64937af182c4716cba0cfaba6c7a2
Signed-off-by: VENKATESH KUMAR <vv770d@att.com>
Issue-ID: DCAEGEN2-271
Signed-off-by: VENKATESH KUMAR <vv770d@att.com>
Signed-off-by: Ladue, David (dl3158) <dl3158@att.com>
diff --git a/Dockerfile b/Dockerfile
index 9475936..d967b0c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -12,7 +12,7 @@
 EXPOSE 162:162/udp
 
 # Copy the current directory contents into the container at ${APPDIR}
-COPY ./bin/ ./bin/
+COPY ./snmptrap/ ./bin/
 COPY ./etc/ ./etc/
 COPY requirements.txt ./
 RUN pip install -r requirements.txt
diff --git a/bin/mod/trapd_file_utils.py b/bin/mod/trapd_file_utils.py
deleted file mode 100644
index e62b528..0000000
--- a/bin/mod/trapd_file_utils.py
+++ /dev/null
@@ -1,225 +0,0 @@
-# ============LICENSE_START=======================================================)
-# org.onap.dcae
-# ================================================================================
-# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
-# ================================================================================
-# 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.
-# ============LICENSE_END=========================================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-"""
-"""
-
-__docformat__ = 'restructuredtext'
-
-# basics
-import datetime
-import errno
-import inspect
-import json
-import logging
-import logging.handlers
-import os
-import sys
-import string
-import time
-import traceback
-import unicodedata
-
-# dcae_snmptrap
-import trapd_settings as tds
-from trapd_logging import ecomp_logger, stdout_logger
-from trapd_exit import cleanup_and_exit
-
-prog_name = os.path.basename(__file__)
-
-
-# # # # # # # # # # # # # # # # # # #
-# fx: roll_all_logs -> roll all logs to timestamped backup
-# # # # # # # # # # ## # # # # # # #
-
-
-def roll_all_logs():
-    """
-    roll all active logs to timestamped version, open new one
-    based on frequency defined in files.roll_frequency
-    """
-
-    # first roll all the eelf files
-    # NOTE:  this will go away when onap logging is standardized/available
-    try:
-        # open various ecomp logs - if any fails, exit
-        for fd in [tds.eelf_error_fd, tds.eelf_debug_fd, tds.eelf_audit_fd,
-                   tds.eelf_metrics_fd, tds.arriving_traps_fd, tds.json_traps_fd]:
-            fd.close()
-
-        roll_file(tds.eelf_error_file_name)
-        roll_file(tds.eelf_debug_file_name)
-        roll_file(tds.eelf_audit_file_name)
-        roll_file(tds.eelf_metrics_file_name)
-
-    except Exception as e:
-        msg = "Error closing logs: " + str(e)
-        stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-    reopened_successfully = open_eelf_logs()
-    if not reopened_successfully:
-        msg = "Error re-opening EELF logs during roll-over to timestamped versions - EXITING"
-        stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-    # json log
-    roll_file(tds.json_traps_filename)
-
-    try:
-        tds.json_traps_fd = open_file(tds.json_traps_filename)
-    except Exception as e:
-        msg = ("Error opening json_log %s : %s" %
-               (json_traps_filename, str(e)))
-        stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-    # arriving trap log
-    roll_file(tds.arriving_traps_filename)
-
-    try:
-        tds.arriving_traps_fd = open_file(tds.arriving_traps_filename)
-    except Exception as e:
-        msg = ("Error opening arriving traps %s : %s" %
-               (arriving_traps_filename, str(e)))
-        stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-
-# # # # # # # # # # # # # # # # # # #
-# fx: setup_ecomp_logs -> log in eelf format until standard
-#     is released for python via LOG-161
-# # # # # # # # # # ## # # # # # # #
-
-
-def open_eelf_logs():
-    """
-    open various (multiple ???) logs
-    """
-
-    try:
-        # open various ecomp logs - if any fails, exit
-
-        tds.eelf_error_file_name = (
-            tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_error'])
-        tds.eelf_error_fd = open_file(tds.eelf_error_file_name)
-
-    except Exception as e:
-        msg = "Error opening eelf error log : " + str(e)
-        stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-    try:
-        tds.eelf_debug_file_name = (
-            tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_debug'])
-        tds.eelf_debug_fd = open_file(tds.eelf_debug_file_name)
-
-    except Exception as e:
-        msg = "Error opening eelf debug log : " + str(e)
-        stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-    try:
-        tds.eelf_audit_file_name = (
-            tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_audit'])
-        tds.eelf_audit_fd = open_file(tds.eelf_audit_file_name)
-    except Exception as e:
-        msg = "Error opening eelf audit log : " + str(e)
-        stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-    try:
-        tds.eelf_metrics_file_name = (
-            tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_metrics'])
-        tds.eelf_metrics_fd = open_file(tds.eelf_metrics_file_name)
-    except Exception as e:
-        msg = "Error opening eelf metric log : " + str(e)
-        stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-    return True
-
-# # # # # # # # # # # # # # # # # # #
-# fx: roll_log_file -> move provided filename to timestamped version
-# # # # # # # # # # ## # # # # # # #
-
-
-def roll_file(_loc_file_name):
-    """
-    move active file to timestamped archive
-    """
-
-    _file_name_suffix = "%s" % (datetime.datetime.fromtimestamp(time.time()).
-                                fromtimestamp(time.time()).
-                                strftime('%Y-%m-%dT%H:%M:%S'))
-
-    _loc_file_name_bak = _loc_file_name + '.' + _file_name_suffix
-
-    # roll existing file if present
-    if os.path.isfile(_loc_file_name):
-        try:
-            os.rename(_loc_file_name, _loc_file_name_bak)
-        except Exception as e:
-            _msg = ("ERROR: Unable to rename %s to %s"
-                    % (_loc_file_name,
-                       _loc_file_name_bak))
-            ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_CRIT,
-                         tds.CODE_GENERAL, _msg)
-
-
-# # # # # # # # # # # # #
-# fx: open_log_file
-# # # # # # # # # # # # #
-
-
-def open_file(_loc_file_name):
-    """
-    open _loc_file_name, return file handle
-    """
-
-    try:
-        # open append mode just in case so nothing is lost, but should be
-        # non-existent file
-        _loc_fd = open(_loc_file_name, 'a')
-        return _loc_fd
-    except Exception as e:
-        msg = "Error opening " + _loc_file_name + " append mode - " + str(e)
-        stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-
-# # # # # # # # # # # # #
-# fx: close_file
-# # # # # # # # # # # # #
-    """
-    close _loc_file_name, return True with success, False otherwise
-    """
-
-
-def close_file(_loc_fd, _loc_filename):
-
-    try:
-        _loc_fd.close()
-        return True
-    except Exception as e:
-        msg = "Error closing %s : %s - results indeterminate" % (
-            _loc_filename, str(e))
-        ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg)
-        return False
diff --git a/coverage.xml b/coverage.xml
new file mode 100644
index 0000000..96da2c6
--- /dev/null
+++ b/coverage.xml
@@ -0,0 +1,695 @@
+<?xml version="1.0" ?>
+<coverage branch-rate="0" branches-covered="0" branches-valid="0" complexity="0" line-rate="0.07154" lines-covered="45" lines-valid="629" timestamp="1522110803348" version="4.5.1">
+	<!-- Generated by coverage.py: https://coverage.readthedocs.io -->
+	<!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
+	<sources>
+		<source>C:\Users\vv770d\git\onap\snmptrap\snmptrap</source>
+	</sources>
+	<packages>
+		<package branch-rate="0" complexity="0" line-rate="0" name=".">
+			<classes>
+				<class branch-rate="0" complexity="0" filename="__init__.py" line-rate="1" name="__init__.py">
+					<methods/>
+					<lines/>
+				</class>
+				<class branch-rate="0" complexity="0" filename="snmptrapd.py" line-rate="0" name="snmptrapd.py">
+					<methods/>
+					<lines>
+						<line hits="0" number="21"/>
+						<line hits="0" number="36"/>
+						<line hits="0" number="39"/>
+						<line hits="0" number="40"/>
+						<line hits="0" number="41"/>
+						<line hits="0" number="42"/>
+						<line hits="0" number="43"/>
+						<line hits="0" number="44"/>
+						<line hits="0" number="45"/>
+						<line hits="0" number="46"/>
+						<line hits="0" number="47"/>
+						<line hits="0" number="48"/>
+						<line hits="0" number="49"/>
+						<line hits="0" number="50"/>
+						<line hits="0" number="51"/>
+						<line hits="0" number="52"/>
+						<line hits="0" number="53"/>
+						<line hits="0" number="54"/>
+						<line hits="0" number="55"/>
+						<line hits="0" number="56"/>
+						<line hits="0" number="57"/>
+						<line hits="0" number="58"/>
+						<line hits="0" number="59"/>
+						<line hits="0" number="60"/>
+						<line hits="0" number="63"/>
+						<line hits="0" number="64"/>
+						<line hits="0" number="66"/>
+						<line hits="0" number="67"/>
+						<line hits="0" number="70"/>
+						<line hits="0" number="71"/>
+						<line hits="0" number="72"/>
+						<line hits="0" number="73"/>
+						<line hits="0" number="74"/>
+						<line hits="0" number="76"/>
+						<line hits="0" number="77"/>
+						<line hits="0" number="79"/>
+						<line hits="0" number="80"/>
+						<line hits="0" number="87"/>
+						<line hits="0" number="98"/>
+						<line hits="0" number="99"/>
+						<line hits="0" number="100"/>
+						<line hits="0" number="108"/>
+						<line hits="0" number="125"/>
+						<line hits="0" number="126"/>
+						<line hits="0" number="128"/>
+						<line hits="0" number="133"/>
+						<line hits="0" number="134"/>
+						<line hits="0" number="136"/>
+						<line hits="0" number="137"/>
+						<line hits="0" number="138"/>
+						<line hits="0" number="139"/>
+						<line hits="0" number="140"/>
+						<line hits="0" number="141"/>
+						<line hits="0" number="145"/>
+						<line hits="0" number="146"/>
+						<line hits="0" number="147"/>
+						<line hits="0" number="148"/>
+						<line hits="0" number="156"/>
+						<line hits="0" number="159"/>
+						<line hits="0" number="160"/>
+						<line hits="0" number="161"/>
+						<line hits="0" number="162"/>
+						<line hits="0" number="163"/>
+						<line hits="0" number="164"/>
+						<line hits="0" number="165"/>
+						<line hits="0" number="166"/>
+						<line hits="0" number="167"/>
+						<line hits="0" number="168"/>
+						<line hits="0" number="171"/>
+						<line hits="0" number="172"/>
+						<line hits="0" number="173"/>
+						<line hits="0" number="174"/>
+						<line hits="0" number="177"/>
+						<line hits="0" number="181"/>
+						<line hits="0" number="198"/>
+						<line hits="0" number="199"/>
+						<line hits="0" number="201"/>
+						<line hits="0" number="209"/>
+						<line hits="0" number="214"/>
+						<line hits="0" number="215"/>
+						<line hits="0" number="217"/>
+						<line hits="0" number="218"/>
+						<line hits="0" number="219"/>
+						<line hits="0" number="221"/>
+						<line hits="0" number="223"/>
+						<line hits="0" number="224"/>
+						<line hits="0" number="226"/>
+						<line hits="0" number="234"/>
+						<line hits="0" number="245"/>
+						<line hits="0" number="247"/>
+						<line hits="0" number="248"/>
+						<line hits="0" number="249"/>
+						<line hits="0" number="251"/>
+						<line hits="0" number="254"/>
+						<line hits="0" number="255"/>
+						<line hits="0" number="258"/>
+						<line hits="0" number="260"/>
+						<line hits="0" number="261"/>
+						<line hits="0" number="263"/>
+						<line hits="0" number="264"/>
+						<line hits="0" number="266"/>
+						<line hits="0" number="267"/>
+						<line hits="0" number="268"/>
+						<line hits="0" number="269"/>
+						<line hits="0" number="271"/>
+						<line hits="0" number="273"/>
+						<line hits="0" number="277"/>
+						<line hits="0" number="279"/>
+						<line hits="0" number="281"/>
+						<line hits="0" number="287"/>
+						<line hits="0" number="289"/>
+						<line hits="0" number="291"/>
+						<line hits="0" number="293"/>
+						<line hits="0" number="294"/>
+						<line hits="0" number="295"/>
+						<line hits="0" number="296"/>
+						<line hits="0" number="298"/>
+						<line hits="0" number="300"/>
+						<line hits="0" number="303"/>
+						<line hits="0" number="304"/>
+						<line hits="0" number="306"/>
+						<line hits="0" number="309"/>
+						<line hits="0" number="310"/>
+						<line hits="0" number="312"/>
+						<line hits="0" number="315"/>
+						<line hits="0" number="317"/>
+						<line hits="0" number="318"/>
+						<line hits="0" number="320"/>
+						<line hits="0" number="322"/>
+						<line hits="0" number="324"/>
+						<line hits="0" number="326"/>
+						<line hits="0" number="327"/>
+						<line hits="0" number="329"/>
+						<line hits="0" number="332"/>
+						<line hits="0" number="333"/>
+						<line hits="0" number="334"/>
+						<line hits="0" number="335"/>
+						<line hits="0" number="342"/>
+						<line hits="0" number="345"/>
+						<line hits="0" number="349"/>
+						<line hits="0" number="357"/>
+						<line hits="0" number="378"/>
+						<line hits="0" number="381"/>
+						<line hits="0" number="384"/>
+						<line hits="0" number="385"/>
+						<line hits="0" number="387"/>
+						<line hits="0" number="389"/>
+						<line hits="0" number="391"/>
+						<line hits="0" number="392"/>
+						<line hits="0" number="393"/>
+						<line hits="0" number="396"/>
+						<line hits="0" number="397"/>
+						<line hits="0" number="398"/>
+						<line hits="0" number="399"/>
+						<line hits="0" number="401"/>
+						<line hits="0" number="402"/>
+						<line hits="0" number="403"/>
+						<line hits="0" number="404"/>
+						<line hits="0" number="406"/>
+						<line hits="0" number="408"/>
+						<line hits="0" number="409"/>
+						<line hits="0" number="411"/>
+						<line hits="0" number="413"/>
+						<line hits="0" number="416"/>
+						<line hits="0" number="418"/>
+						<line hits="0" number="419"/>
+						<line hits="0" number="423"/>
+						<line hits="0" number="424"/>
+						<line hits="0" number="425"/>
+						<line hits="0" number="426"/>
+						<line hits="0" number="428"/>
+						<line hits="0" number="429"/>
+						<line hits="0" number="430"/>
+						<line hits="0" number="431"/>
+						<line hits="0" number="434"/>
+						<line hits="0" number="435"/>
+						<line hits="0" number="436"/>
+						<line hits="0" number="438"/>
+						<line hits="0" number="439"/>
+						<line hits="0" number="441"/>
+						<line hits="0" number="442"/>
+						<line hits="0" number="444"/>
+						<line hits="0" number="446"/>
+						<line hits="0" number="447"/>
+						<line hits="0" number="448"/>
+						<line hits="0" number="449"/>
+						<line hits="0" number="451"/>
+						<line hits="0" number="452"/>
+						<line hits="0" number="454"/>
+						<line hits="0" number="455"/>
+						<line hits="0" number="462"/>
+						<line hits="0" number="480"/>
+						<line hits="0" number="482"/>
+						<line hits="0" number="485"/>
+						<line hits="0" number="486"/>
+						<line hits="0" number="487"/>
+						<line hits="0" number="489"/>
+						<line hits="0" number="490"/>
+						<line hits="0" number="491"/>
+						<line hits="0" number="493"/>
+						<line hits="0" number="494"/>
+						<line hits="0" number="495"/>
+						<line hits="0" number="496"/>
+						<line hits="0" number="500"/>
+						<line hits="0" number="502"/>
+						<line hits="0" number="503"/>
+						<line hits="0" number="504"/>
+						<line hits="0" number="505"/>
+						<line hits="0" number="507"/>
+						<line hits="0" number="511"/>
+						<line hits="0" number="512"/>
+						<line hits="0" number="517"/>
+						<line hits="0" number="538"/>
+						<line hits="0" number="539"/>
+						<line hits="0" number="542"/>
+						<line hits="0" number="554"/>
+						<line hits="0" number="555"/>
+						<line hits="0" number="556"/>
+						<line hits="0" number="559"/>
+						<line hits="0" number="560"/>
+						<line hits="0" number="561"/>
+						<line hits="0" number="565"/>
+						<line hits="0" number="569"/>
+						<line hits="0" number="573"/>
+						<line hits="0" number="576"/>
+						<line hits="0" number="581"/>
+						<line hits="0" number="586"/>
+						<line hits="0" number="588"/>
+						<line hits="0" number="589"/>
+						<line hits="0" number="592"/>
+						<line hits="0" number="593"/>
+						<line hits="0" number="595"/>
+						<line hits="0" number="596"/>
+						<line hits="0" number="597"/>
+						<line hits="0" number="598"/>
+						<line hits="0" number="599"/>
+						<line hits="0" number="600"/>
+						<line hits="0" number="602"/>
+						<line hits="0" number="604"/>
+						<line hits="0" number="607"/>
+						<line hits="0" number="610"/>
+						<line hits="0" number="611"/>
+						<line hits="0" number="613"/>
+						<line hits="0" number="615"/>
+						<line hits="0" number="616"/>
+						<line hits="0" number="617"/>
+						<line hits="0" number="618"/>
+						<line hits="0" number="620"/>
+						<line hits="0" number="627"/>
+						<line hits="0" number="629"/>
+						<line hits="0" number="631"/>
+						<line hits="0" number="635"/>
+						<line hits="0" number="638"/>
+						<line hits="0" number="639"/>
+						<line hits="0" number="642"/>
+						<line hits="0" number="643"/>
+						<line hits="0" number="646"/>
+						<line hits="0" number="649"/>
+						<line hits="0" number="652"/>
+						<line hits="0" number="653"/>
+						<line hits="0" number="655"/>
+						<line hits="0" number="665"/>
+						<line hits="0" number="668"/>
+						<line hits="0" number="669"/>
+						<line hits="0" number="670"/>
+						<line hits="0" number="671"/>
+						<line hits="0" number="674"/>
+						<line hits="0" number="677"/>
+						<line hits="0" number="678"/>
+						<line hits="0" number="679"/>
+						<line hits="0" number="680"/>
+						<line hits="0" number="683"/>
+						<line hits="0" number="685"/>
+						<line hits="0" number="686"/>
+						<line hits="0" number="687"/>
+						<line hits="0" number="688"/>
+						<line hits="0" number="691"/>
+						<line hits="0" number="694"/>
+						<line hits="0" number="696"/>
+						<line hits="0" number="697"/>
+						<line hits="0" number="698"/>
+						<line hits="0" number="701"/>
+						<line hits="0" number="705"/>
+						<line hits="0" number="713"/>
+						<line hits="0" number="714"/>
+						<line hits="0" number="715"/>
+						<line hits="0" number="717"/>
+						<line hits="0" number="718"/>
+						<line hits="0" number="724"/>
+						<line hits="0" number="725"/>
+						<line hits="0" number="727"/>
+						<line hits="0" number="728"/>
+						<line hits="0" number="729"/>
+						<line hits="0" number="731"/>
+						<line hits="0" number="732"/>
+						<line hits="0" number="733"/>
+						<line hits="0" number="734"/>
+						<line hits="0" number="747"/>
+						<line hits="0" number="748"/>
+						<line hits="0" number="749"/>
+						<line hits="0" number="751"/>
+						<line hits="0" number="752"/>
+						<line hits="0" number="758"/>
+						<line hits="0" number="759"/>
+						<line hits="0" number="761"/>
+						<line hits="0" number="762"/>
+						<line hits="0" number="763"/>
+						<line hits="0" number="765"/>
+						<line hits="0" number="766"/>
+						<line hits="0" number="767"/>
+						<line hits="0" number="768"/>
+						<line hits="0" number="778"/>
+						<line hits="0" number="781"/>
+						<line hits="0" number="787"/>
+						<line hits="0" number="794"/>
+						<line hits="0" number="796"/>
+						<line hits="0" number="799"/>
+						<line hits="0" number="800"/>
+						<line hits="0" number="801"/>
+						<line hits="0" number="802"/>
+						<line hits="0" number="803"/>
+						<line hits="0" number="804"/>
+					</lines>
+				</class>
+			</classes>
+		</package>
+		<package branch-rate="0" complexity="0" line-rate="0.1466" name="mod">
+			<classes>
+				<class branch-rate="0" complexity="0" filename="mod/__init__.py" line-rate="1" name="__init__.py">
+					<methods/>
+					<lines/>
+				</class>
+				<class branch-rate="0" complexity="0" filename="mod/trapd_exit.py" line-rate="1" name="trapd_exit.py">
+					<methods/>
+					<lines>
+						<line hits="1" number="21"/>
+						<line hits="1" number="26"/>
+						<line hits="1" number="28"/>
+						<line hits="1" number="29"/>
+						<line hits="1" number="30"/>
+						<line hits="1" number="31"/>
+						<line hits="1" number="33"/>
+						<line hits="1" number="41"/>
+						<line hits="1" number="59"/>
+						<line hits="1" number="61"/>
+						<line hits="1" number="62"/>
+						<line hits="1" number="63"/>
+					</lines>
+				</class>
+				<class branch-rate="0" complexity="0" filename="mod/trapd_file_utils.py" line-rate="0" name="trapd_file_utils.py">
+					<methods/>
+					<lines>
+						<line hits="0" number="21"/>
+						<line hits="0" number="24"/>
+						<line hits="0" number="27"/>
+						<line hits="0" number="28"/>
+						<line hits="0" number="29"/>
+						<line hits="0" number="30"/>
+						<line hits="0" number="31"/>
+						<line hits="0" number="32"/>
+						<line hits="0" number="33"/>
+						<line hits="0" number="34"/>
+						<line hits="0" number="35"/>
+						<line hits="0" number="36"/>
+						<line hits="0" number="37"/>
+						<line hits="0" number="38"/>
+						<line hits="0" number="41"/>
+						<line hits="0" number="42"/>
+						<line hits="0" number="43"/>
+						<line hits="0" number="45"/>
+						<line hits="0" number="53"/>
+						<line hits="0" number="61"/>
+						<line hits="0" number="63"/>
+						<line hits="0" number="65"/>
+						<line hits="0" number="67"/>
+						<line hits="0" number="68"/>
+						<line hits="0" number="69"/>
+						<line hits="0" number="70"/>
+						<line hits="0" number="72"/>
+						<line hits="0" number="73"/>
+						<line hits="0" number="74"/>
+						<line hits="0" number="75"/>
+						<line hits="0" number="77"/>
+						<line hits="0" number="78"/>
+						<line hits="0" number="79"/>
+						<line hits="0" number="80"/>
+						<line hits="0" number="81"/>
+						<line hits="0" number="84"/>
+						<line hits="0" number="86"/>
+						<line hits="0" number="87"/>
+						<line hits="0" number="88"/>
+						<line hits="0" number="89"/>
+						<line hits="0" number="91"/>
+						<line hits="0" number="92"/>
+						<line hits="0" number="95"/>
+						<line hits="0" number="97"/>
+						<line hits="0" number="98"/>
+						<line hits="0" number="99"/>
+						<line hits="0" number="100"/>
+						<line hits="0" number="102"/>
+						<line hits="0" number="103"/>
+						<line hits="0" number="112"/>
+						<line hits="0" number="117"/>
+						<line hits="0" number="120"/>
+						<line hits="0" number="122"/>
+						<line hits="0" number="124"/>
+						<line hits="0" number="125"/>
+						<line hits="0" number="126"/>
+						<line hits="0" number="127"/>
+						<line hits="0" number="129"/>
+						<line hits="0" number="130"/>
+						<line hits="0" number="132"/>
+						<line hits="0" number="134"/>
+						<line hits="0" number="135"/>
+						<line hits="0" number="136"/>
+						<line hits="0" number="137"/>
+						<line hits="0" number="139"/>
+						<line hits="0" number="140"/>
+						<line hits="0" number="142"/>
+						<line hits="0" number="143"/>
+						<line hits="0" number="144"/>
+						<line hits="0" number="145"/>
+						<line hits="0" number="146"/>
+						<line hits="0" number="148"/>
+						<line hits="0" number="149"/>
+						<line hits="0" number="151"/>
+						<line hits="0" number="152"/>
+						<line hits="0" number="153"/>
+						<line hits="0" number="154"/>
+						<line hits="0" number="155"/>
+						<line hits="0" number="157"/>
+						<line hits="0" number="164"/>
+						<line hits="0" number="169"/>
+						<line hits="0" number="173"/>
+						<line hits="0" number="176"/>
+						<line hits="0" number="177"/>
+						<line hits="0" number="178"/>
+						<line hits="0" number="179"/>
+						<line hits="0" number="180"/>
+						<line hits="0" number="183"/>
+						<line hits="0" number="192"/>
+						<line hits="0" number="197"/>
+						<line hits="0" number="200"/>
+						<line hits="0" number="201"/>
+						<line hits="0" number="202"/>
+						<line hits="0" number="203"/>
+						<line hits="0" number="204"/>
+						<line hits="0" number="205"/>
+						<line hits="0" number="211"/>
+						<line hits="0" number="216"/>
+						<line hits="0" number="218"/>
+						<line hits="0" number="219"/>
+						<line hits="0" number="220"/>
+						<line hits="0" number="221"/>
+						<line hits="0" number="222"/>
+						<line hits="0" number="224"/>
+						<line hits="0" number="225"/>
+					</lines>
+				</class>
+				<class branch-rate="0" complexity="0" filename="mod/trapd_get_cbs_config.py" line-rate="0" name="trapd_get_cbs_config.py">
+					<methods/>
+					<lines>
+						<line hits="0" number="21"/>
+						<line hits="0" number="27"/>
+						<line hits="0" number="29"/>
+						<line hits="0" number="30"/>
+						<line hits="0" number="31"/>
+						<line hits="0" number="32"/>
+						<line hits="0" number="33"/>
+						<line hits="0" number="34"/>
+						<line hits="0" number="35"/>
+						<line hits="0" number="37"/>
+						<line hits="0" number="38"/>
+						<line hits="0" number="39"/>
+						<line hits="0" number="40"/>
+						<line hits="0" number="42"/>
+						<line hits="0" number="50"/>
+						<line hits="0" number="58"/>
+						<line hits="0" number="61"/>
+						<line hits="0" number="62"/>
+						<line hits="0" number="63"/>
+						<line hits="0" number="64"/>
+						<line hits="0" number="65"/>
+						<line hits="0" number="68"/>
+						<line hits="0" number="69"/>
+						<line hits="0" number="70"/>
+						<line hits="0" number="72"/>
+						<line hits="0" number="73"/>
+						<line hits="0" number="74"/>
+						<line hits="0" number="75"/>
+						<line hits="0" number="76"/>
+						<line hits="0" number="77"/>
+						<line hits="0" number="79"/>
+						<line hits="0" number="80"/>
+						<line hits="0" number="81"/>
+						<line hits="0" number="82"/>
+						<line hits="0" number="84"/>
+						<line hits="0" number="86"/>
+						<line hits="0" number="87"/>
+						<line hits="0" number="88"/>
+						<line hits="0" number="89"/>
+						<line hits="0" number="90"/>
+						<line hits="0" number="92"/>
+						<line hits="0" number="93"/>
+						<line hits="0" number="96"/>
+						<line hits="0" number="97"/>
+						<line hits="0" number="98"/>
+						<line hits="0" number="99"/>
+						<line hits="0" number="102"/>
+						<line hits="0" number="103"/>
+						<line hits="0" number="104"/>
+						<line hits="0" number="105"/>
+						<line hits="0" number="108"/>
+						<line hits="0" number="109"/>
+						<line hits="0" number="110"/>
+						<line hits="0" number="111"/>
+						<line hits="0" number="113"/>
+						<line hits="0" number="114"/>
+						<line hits="0" number="115"/>
+						<line hits="0" number="116"/>
+						<line hits="0" number="118"/>
+					</lines>
+				</class>
+				<class branch-rate="0" complexity="0" filename="mod/trapd_http_session.py" line-rate="0.8333" name="trapd_http_session.py">
+					<methods/>
+					<lines>
+						<line hits="1" number="21"/>
+						<line hits="1" number="26"/>
+						<line hits="1" number="28"/>
+						<line hits="1" number="29"/>
+						<line hits="1" number="30"/>
+						<line hits="1" number="32"/>
+						<line hits="1" number="38"/>
+						<line hits="1" number="53"/>
+						<line hits="1" number="54"/>
+						<line hits="0" number="55"/>
+						<line hits="0" number="56"/>
+						<line hits="1" number="58"/>
+					</lines>
+				</class>
+				<class branch-rate="0" complexity="0" filename="mod/trapd_logging.py" line-rate="0" name="trapd_logging.py">
+					<methods/>
+					<lines>
+						<line hits="0" number="21"/>
+						<line hits="0" number="24"/>
+						<line hits="0" number="27"/>
+						<line hits="0" number="28"/>
+						<line hits="0" number="29"/>
+						<line hits="0" number="30"/>
+						<line hits="0" number="31"/>
+						<line hits="0" number="32"/>
+						<line hits="0" number="33"/>
+						<line hits="0" number="34"/>
+						<line hits="0" number="35"/>
+						<line hits="0" number="36"/>
+						<line hits="0" number="37"/>
+						<line hits="0" number="38"/>
+						<line hits="0" number="40"/>
+						<line hits="0" number="42"/>
+						<line hits="0" number="50"/>
+						<line hits="0" number="124"/>
+						<line hits="0" number="132"/>
+						<line hits="0" number="133"/>
+						<line hits="0" number="140"/>
+						<line hits="0" number="141"/>
+						<line hits="0" number="142"/>
+						<line hits="0" number="144"/>
+						<line hits="0" number="145"/>
+						<line hits="0" number="147"/>
+						<line hits="0" number="149"/>
+						<line hits="0" number="150"/>
+						<line hits="0" number="152"/>
+						<line hits="0" number="153"/>
+						<line hits="0" number="155"/>
+						<line hits="0" number="157"/>
+						<line hits="0" number="158"/>
+						<line hits="0" number="160"/>
+						<line hits="0" number="162"/>
+						<line hits="0" number="170"/>
+						<line hits="0" number="172"/>
+						<line hits="0" number="174"/>
+						<line hits="0" number="181"/>
+						<line hits="0" number="196"/>
+						<line hits="0" number="199"/>
+					</lines>
+				</class>
+				<class branch-rate="0" complexity="0" filename="mod/trapd_runtime_pid.py" line-rate="0.8846" name="trapd_runtime_pid.py">
+					<methods/>
+					<lines>
+						<line hits="1" number="21"/>
+						<line hits="1" number="26"/>
+						<line hits="1" number="28"/>
+						<line hits="1" number="29"/>
+						<line hits="1" number="30"/>
+						<line hits="1" number="31"/>
+						<line hits="1" number="32"/>
+						<line hits="1" number="34"/>
+						<line hits="1" number="40"/>
+						<line hits="1" number="54"/>
+						<line hits="1" number="55"/>
+						<line hits="1" number="56"/>
+						<line hits="1" number="57"/>
+						<line hits="1" number="58"/>
+						<line hits="1" number="59"/>
+						<line hits="1" number="60"/>
+						<line hits="1" number="66"/>
+						<line hits="1" number="72"/>
+						<line hits="1" number="85"/>
+						<line hits="1" number="86"/>
+						<line hits="1" number="87"/>
+						<line hits="1" number="88"/>
+						<line hits="1" number="90"/>
+						<line hits="0" number="92"/>
+						<line hits="0" number="93"/>
+						<line hits="0" number="94"/>
+					</lines>
+				</class>
+				<class branch-rate="0" complexity="0" filename="mod/trapd_settings.py" line-rate="0" name="trapd_settings.py">
+					<methods/>
+					<lines>
+						<line hits="0" number="21"/>
+						<line hits="0" number="24"/>
+						<line hits="0" number="27"/>
+						<line hits="0" number="32"/>
+						<line hits="0" number="43"/>
+						<line hits="0" number="45"/>
+						<line hits="0" number="50"/>
+						<line hits="0" number="52"/>
+						<line hits="0" number="55"/>
+						<line hits="0" number="57"/>
+						<line hits="0" number="60"/>
+						<line hits="0" number="62"/>
+						<line hits="0" number="65"/>
+						<line hits="0" number="67"/>
+						<line hits="0" number="70"/>
+						<line hits="0" number="72"/>
+						<line hits="0" number="74"/>
+						<line hits="0" number="79"/>
+						<line hits="0" number="81"/>
+						<line hits="0" number="83"/>
+						<line hits="0" number="85"/>
+						<line hits="0" number="87"/>
+						<line hits="0" number="89"/>
+						<line hits="0" number="94"/>
+						<line hits="0" number="96"/>
+						<line hits="0" number="98"/>
+						<line hits="0" number="100"/>
+						<line hits="0" number="102"/>
+						<line hits="0" number="104"/>
+						<line hits="0" number="106"/>
+						<line hits="0" number="108"/>
+						<line hits="0" number="113"/>
+						<line hits="0" number="118"/>
+						<line hits="0" number="120"/>
+						<line hits="0" number="125"/>
+						<line hits="0" number="127"/>
+						<line hits="0" number="132"/>
+						<line hits="0" number="141"/>
+						<line hits="0" number="142"/>
+						<line hits="0" number="143"/>
+						<line hits="0" number="144"/>
+						<line hits="0" number="145"/>
+						<line hits="0" number="146"/>
+						<line hits="0" number="155"/>
+						<line hits="0" number="156"/>
+						<line hits="0" number="157"/>
+						<line hits="0" number="158"/>
+						<line hits="0" number="159"/>
+						<line hits="0" number="160"/>
+						<line hits="0" number="161"/>
+						<line hits="0" number="164"/>
+						<line hits="0" number="167"/>
+					</lines>
+				</class>
+			</classes>
+		</package>
+	</packages>
+</coverage>
diff --git a/pom.xml b/pom.xml
index 17b54e7..5ce191a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,7 +34,7 @@
   <url>http://maven.apache.org</url>
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <sonar.skip>true</sonar.skip>
+    <sonar.skip>false</sonar.skip>
     <sonar.sources>.</sonar.sources>
     <!-- customize the SONARQUBE URL -->
     <!-- sonar.host.url>http://localhost:9000</sonar.host.url -->
@@ -43,6 +43,7 @@
     <sonar.language>py</sonar.language>
     <sonar.pluginName>Python</sonar.pluginName>
     <sonar.inclusions>**/*.py</sonar.inclusions>
+    <sonar.exclusions>target/**,tests/**,setup.py,**/__init__.py</sonar.exclusions>
     <!-- for JavaScaript -->
     <!--
     <sonar.language>js</sonar.language>
diff --git a/setup.py b/setup.py
index 54b785d..edb5aa3 100644
--- a/setup.py
+++ b/setup.py
@@ -20,19 +20,23 @@
 import os
 import string
 import sys
+import setuptools
+from setuptools import setup, find_packages
 
-install_reqs = parse_requirements("requirements.txt", session=PipSession())
-reqs = [str(ir.req) for ir in install_reqs]
 
 setup(
-    name = "dcaegen2-collectors-snmptrap",
+    name = "snmptrap",
     description = "snmp trap receiver for ONAP docker image",
     version = "1.3.0",
     packages=find_packages(),
+    install_requires=[
+	"pysnmp==4.4.2",
+	"requests==2.18.3",
+	"onap_dcae_cbs_docker_client==0.0.3"
+    ],
     author = "Dave L",
     author_email = "dl3158@att.com",
     license='Apache 2',
     keywords = "",
-    url = "",
-    install_requires=reqs
+    url = ""
 )
diff --git a/snmptrap/__init__.py b/snmptrap/__init__.py
new file mode 100644
index 0000000..1875bf6
--- /dev/null
+++ b/snmptrap/__init__.py
@@ -0,0 +1,21 @@
+# ================================================================================
+# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+
+# empty __init__.py so that pytest can add correct path to coverage report, -- per pytest
+# best practice guideline
diff --git a/snmptrap/mod/__init__.py b/snmptrap/mod/__init__.py
new file mode 100644
index 0000000..1875bf6
--- /dev/null
+++ b/snmptrap/mod/__init__.py
@@ -0,0 +1,21 @@
+# ================================================================================
+# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+
+# empty __init__.py so that pytest can add correct path to coverage report, -- per pytest
+# best practice guideline
diff --git a/bin/mod/trapd_exit.py b/snmptrap/mod/trapd_exit.py
similarity index 96%
rename from bin/mod/trapd_exit.py
rename to snmptrap/mod/trapd_exit.py
index a7ffc8a..ef7a2ae 100644
--- a/bin/mod/trapd_exit.py
+++ b/snmptrap/mod/trapd_exit.py
@@ -56,8 +56,8 @@
         number of parameters passed to module
     """
 
-    _num_params = len(locals())
+    # _num_params = len(locals())
 
-    if _num_params == 2:
+    if _pid_file_name is not None:
         rc = rm_pid(_pid_file_name)
     sys.exit(_loc_exit_code)
diff --git a/bin/mod/trapd_get_cbs_config.py b/snmptrap/mod/trapd_get_cbs_config.py
similarity index 95%
rename from bin/mod/trapd_get_cbs_config.py
rename to snmptrap/mod/trapd_get_cbs_config.py
index e0f5ca8..524f1c2 100644
--- a/bin/mod/trapd_get_cbs_config.py
+++ b/snmptrap/mod/trapd_get_cbs_config.py
@@ -37,7 +37,7 @@
 import trapd_settings as tds
 from onap_dcae_cbs_docker_client.client import get_config
 from trapd_exit import cleanup_and_exit
-from trapd_logging import stdout_logger
+from trapd_io import stdout_logger
 
 prog_name = os.path.basename(__file__)
 
@@ -74,12 +74,12 @@
         except Exception as e:
             msg = "CBS_SIM_JSON not defined - FATAL ERROR, exiting"
             stdout_logger(msg)
-            cleanup_and_exit(1, pid_file_name)
+            cleanup_and_exit(1,None)
 
         if _cbs_sim_json_file == "None":
             msg = "CBS_SIM_JSON not defined - FATAL ERROR, exiting"
             stdout_logger(msg)
-            cleanup_and_exit(1, pid_file_name)
+            cleanup_and_exit(1,None)
         else:
             msg = ("ONAP controller override specified via CBS_SIM_JSON: %s" %
                    _cbs_sim_json_file)
@@ -90,7 +90,7 @@
                 msg = "Unable to load CBS_SIM_JSON " + _cbs_sim_json_file + \
                     " (invalid json?) - FATAL ERROR, exiting"
                 stdout_logger(msg)
-                cleanup_and_exit(1, tds.pid_file_name)
+                cleanup_and_exit(1,None)
 
     # recalc timeout, set default if not present
     try:
diff --git a/bin/mod/trapd_http_session.py b/snmptrap/mod/trapd_http_session.py
similarity index 100%
rename from bin/mod/trapd_http_session.py
rename to snmptrap/mod/trapd_http_session.py
diff --git a/snmptrap/mod/trapd_io.py b/snmptrap/mod/trapd_io.py
new file mode 100644
index 0000000..8667750
--- /dev/null
+++ b/snmptrap/mod/trapd_io.py
@@ -0,0 +1,396 @@
+# ============LICENSE_START=======================================================)
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+"""
+"""
+
+__docformat__ = 'restructuredtext'
+
+# basics
+import datetime
+import errno
+import inspect
+import json
+import logging
+import logging.handlers
+import os
+import sys
+import string
+import time
+import traceback
+import unicodedata
+
+# dcae_snmptrap
+import trapd_settings as tds
+from trapd_exit import cleanup_and_exit
+
+prog_name = os.path.basename(__file__)
+
+
+# # # # # # # # # # # # # # # # # # #
+# fx: roll_all_logs -> roll all logs to timestamped backup
+# # # # # # # # # # ## # # # # # # #
+
+
+def roll_all_logs():
+    """
+    roll all active logs to timestamped version, open new one
+    based on frequency defined in files.roll_frequency
+    """
+
+    # first roll all the eelf files
+    # NOTE:  this will go away when onap logging is standardized/available
+    try:
+        # open various ecomp logs - if any fails, exit
+        for fd in [tds.eelf_error_fd, tds.eelf_debug_fd, tds.eelf_audit_fd,
+                   tds.eelf_metrics_fd, tds.arriving_traps_fd, tds.json_traps_fd]:
+            fd.close()
+
+        roll_file(tds.eelf_error_file_name)
+        roll_file(tds.eelf_debug_file_name)
+        roll_file(tds.eelf_audit_file_name)
+        roll_file(tds.eelf_metrics_file_name)
+
+    except Exception as e:
+        msg = "Error closing logs: " + str(e)
+        stdout_logger(msg)
+        cleanup_and_exit(1, tds.pid_file_name)
+
+    reopened_successfully = open_eelf_logs()
+    if not reopened_successfully:
+        msg = "Error re-opening EELF logs during roll-over to timestamped versions - EXITING"
+        stdout_logger(msg)
+        cleanup_and_exit(1, tds.pid_file_name)
+
+    # json log
+    roll_file(tds.json_traps_filename)
+
+    try:
+        tds.json_traps_fd = open_file(tds.json_traps_filename)
+    except Exception as e:
+        msg = ("Error opening json_log %s : %s" %
+               (json_traps_filename, str(e)))
+        stdout_logger(msg)
+        cleanup_and_exit(1, tds.pid_file_name)
+
+    # arriving trap log
+    roll_file(tds.arriving_traps_filename)
+
+    try:
+        tds.arriving_traps_fd = open_file(tds.arriving_traps_filename)
+    except Exception as e:
+        msg = ("Error opening arriving traps %s : %s" %
+               (arriving_traps_filename, str(e)))
+        stdout_logger(msg)
+        cleanup_and_exit(1, tds.pid_file_name)
+
+
+# # # # # # # # # # # # # # # # # # #
+# fx: setup_ecomp_logs -> log in eelf format until standard
+#     is released for python via LOG-161
+# # # # # # # # # # ## # # # # # # #
+
+
+def open_eelf_logs():
+    """
+    open various (multiple ???) logs
+    """
+
+    try:
+        # open various ecomp logs - if any fails, exit
+
+        tds.eelf_error_file_name = (
+            tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_error'])
+        tds.eelf_error_fd = open_file(tds.eelf_error_file_name)
+
+    except Exception as e:
+        msg = "Error opening eelf error log : " + str(e)
+        stdout_logger(msg)
+        cleanup_and_exit(1, tds.pid_file_name)
+
+    try:
+        tds.eelf_debug_file_name = (
+            tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_debug'])
+        tds.eelf_debug_fd = open_file(tds.eelf_debug_file_name)
+
+    except Exception as e:
+        msg = "Error opening eelf debug log : " + str(e)
+        stdout_logger(msg)
+        cleanup_and_exit(1, tds.pid_file_name)
+
+    try:
+        tds.eelf_audit_file_name = (
+            tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_audit'])
+        tds.eelf_audit_fd = open_file(tds.eelf_audit_file_name)
+    except Exception as e:
+        msg = "Error opening eelf audit log : " + str(e)
+        stdout_logger(msg)
+        cleanup_and_exit(1, tds.pid_file_name)
+
+    try:
+        tds.eelf_metrics_file_name = (
+            tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_metrics'])
+        tds.eelf_metrics_fd = open_file(tds.eelf_metrics_file_name)
+    except Exception as e:
+        msg = "Error opening eelf metric log : " + str(e)
+        stdout_logger(msg)
+        cleanup_and_exit(1, tds.pid_file_name)
+
+    return True
+
+# # # # # # # # # # # # # # # # # # #
+# fx: roll_log_file -> move provided filename to timestamped version
+# # # # # # # # # # ## # # # # # # #
+
+
+def roll_file(_loc_file_name):
+    """
+    move active file to timestamped archive
+    """
+
+    _file_name_suffix = "%s" % (datetime.datetime.fromtimestamp(time.time()).
+                                fromtimestamp(time.time()).
+                                strftime('%Y-%m-%dT%H:%M:%S'))
+
+    _loc_file_name_bak = _loc_file_name + '.' + _file_name_suffix
+
+    # roll existing file if present
+    if os.path.isfile(_loc_file_name):
+        try:
+            os.rename(_loc_file_name, _loc_file_name_bak)
+        except Exception as e:
+            _msg = ("ERROR: Unable to rename %s to %s"
+                    % (_loc_file_name,
+                       _loc_file_name_bak))
+            ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_CRIT,
+                         tds.CODE_GENERAL, _msg)
+
+
+# # # # # # # # # # # # #
+# fx: open_log_file
+# # # # # # # # # # # # #
+
+
+def open_file(_loc_file_name):
+    """
+    open _loc_file_name, return file handle
+    """
+
+    try:
+        # open append mode just in case so nothing is lost, but should be
+        # non-existent file
+        _loc_fd = open(_loc_file_name, 'a')
+        return _loc_fd
+    except Exception as e:
+        msg = "Error opening " + _loc_file_name + " append mode - " + str(e)
+        stdout_logger(msg)
+        cleanup_and_exit(1, tds.pid_file_name)
+
+
+# # # # # # # # # # # # #
+# fx: close_file
+# # # # # # # # # # # # #
+    """
+    close _loc_file_name, return True with success, False otherwise
+    """
+
+
+def close_file(_loc_fd, _loc_filename):
+
+    try:
+        _loc_fd.close()
+        return True
+    except Exception as e:
+        msg = "Error closing %s : %s - results indeterminate" % (
+            _loc_filename, str(e))
+        ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg)
+        return False
+
+# # # # # # # # # # # # # # # # # # #
+# fx: ecomp_logger -> log in eelf format until standard
+#     is released for python via LOG-161
+# # # # # # # # # # ## # # # # # # #
+
+def ecomp_logger(_log_type, _sev, _error_code, _msg):
+    """
+    Log to ecomp-style logfiles.  Logs include:
+
+    Note:  this will be updated when https://jira.onap.org/browse/LOG-161
+    is closed/available; until then, we resort to a generic format with
+    valuable info in "extra=" field (?)
+
+    :Parameters:
+       _msg -
+    :Exceptions:
+       none
+    :Keywords:
+       eelf logging
+    :Log Styles:
+
+       :error.log:
+
+       if CommonLogger.verbose: print("using CommonLogger.ErrorFile")
+          self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
+          % (requestID, threadID, serviceName, partnerName, targetEntity, targetServiceName,
+             errorCategory, errorCode, errorDescription, detailMessage))
+
+       error.log example:
+
+       2018-02-20T07:21:34,007+00:00||MainThread|snmp_log_monitor||||FATAL|900||Tue Feb 20 07:21:11 UTC 2018 CRITICAL: [a0cae74e-160e-11e8-8f9f-0242ac110002] ALL publish attempts failed to DMAPP server: dcae-mrtr-zltcrdm5bdce1.1dff83.rdm5b.tci.att.com, topic: DCAE-COLLECTOR-UCSNMP, 339 trap(s) not published in epoch_serno range: 15191112530000 - 15191112620010
+
+       :debug.log:
+
+       if CommonLogger.verbose: print("using CommonLogger.DebugFile")
+          self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
+          % (requestID, threadID, serverName, serviceName, instanceUUID, upperLogLevel,
+          severity, serverIPAddress, server, IPAddress, className, timer, detailMessage))
+
+       debug.log example:
+
+         none available
+
+       :audit.log:
+
+       if CommonLogger.verbose: print("using CommonLogger.AuditFile")
+       endAuditTime, endAuditMsec = self._getTime()
+       if self._begTime is not None:
+          d = {'begtime': self._begTime, 'begmsecs': self._begMsec, 'endtime': endAuditTime,
+               'endmsecs': endAuditMsec}
+       else:
+          d = {'begtime': endAuditTime, 'begmsecs': endAuditMsec, 'endtime': endAuditTime,
+               'endmsecs': endAuditMsec}
+
+       self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
+       % (requestID, serviceInstanceID, threadID, serverName, serviceName, partnerName,
+       statusCode, responseCode, responseDescription, instanceUUID, upperLogLevel,
+       severity, serverIPAddress, timer, server, IPAddress, className, unused,
+       processKey, customField1, customField2, customField3, customField4,
+       detailMessage), extra=d)
+
+
+       :metrics.log:
+
+          self._logger.log(50,'%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
+          % (requestID, serviceInstanceID, threadID, serverName, serviceName, partnerName,
+          targetEntity, targetServiceName, statusCode, responseCode, responseDescription,
+          instanceUUID, upperLogLevel, severity, serverIPAddress, timer, server,
+          IPAddress,
+          className, unused, processKey, targetVirtualEntity, customField1, customField2,
+          customField3, customField4, detailMessage), extra=d)
+
+       metrics.log example:
+
+          none available
+
+
+    """
+
+    unused = ""
+
+    # ct = time.time()
+    # lt = time.localtime(ct)
+    # t_hman = time.strftime(DateFmt, lt)
+    # t_ms = (ct - int(ct)) * 1000
+    # above were various attempts at setting time string found in other
+    # libs; instead, let's keep it real:
+    t_out = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S,%f")[:-3]
+    calling_fx = inspect.stack()[1][3]
+
+    # FIXME: this entire module is a hack to override concept of prog logging
+    #        written across multiple files (???), making diagnostics IMPOSSIBLE!
+    #        Hoping to leverage ONAP logging libraries & standards when available
+
+    # catch invalid log type
+    if _log_type < 1 or _log_type > 5:
+        msg = ("INVALID log type: %s " % _log_type)
+        _out_rec = ("%s|%s|%s|%s|%s|%s|%s|%s|%s"
+                    % ((calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, (msg + _msg))))
+        try:
+            tds.eelf_error_fd.write('%s|%s\n' % (t_out, str(_out_rec)))
+        except Exception as e:
+            stdout_logger(str(_out_rec))
+
+        return False
+
+    if _sev >= tds.minimum_severity_to_log:
+        # log to appropriate eelf log (different files ??)
+        if _log_type == tds.LOG_TYPE_ERROR:
+            _out_rec = ('%s|%s|%s|%s|%s|%s|%s|%s|%s'
+                        % ((calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, _msg)))
+            try:
+                tds.eelf_error_fd.write('%s|%s\n' % (t_out, str(_out_rec)))
+            except Exception as e:
+                stdout_logger(str(_out_rec))
+        elif _log_type == tds.LOG_TYPE_AUDIT:
+            # log message in AUDIT format
+            _out_rec = ('%s|%s|%s|%s|%s|%s|%s|%s|%s'
+                        % ((calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, _msg)))
+            try:
+                tds.eelf_audit_fd.write('%s|%s\n' % (t_out, str(_out_rec)))
+            except Exception as e:
+                stdout_logger(str(_out_rec))
+        elif _log_type == tds.LOG_TYPE_METRICS:
+            # log message in METRICS format
+            _out_rec = ('%s|%s|%s|%s|%s|%s|%s|%s|%s'
+                        % ((calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, _msg)))
+            try:
+                tds.eelf_metrics_fd.write('%s|%s\n' % (t_out, str(_out_rec)))
+            except Exception as e:
+                stdout_logger(str(_out_rec))
+
+        # DEBUG *AND* others - there *MUST BE* a single time-sequenced log for diagnostics!
+        # FIXME: too much I/O !!!
+        # always write to debug; we need ONE logfile that has time-sequence full view !!!
+        # if (_log_type == tds.LOG_TYPE_DEBUG and _sev >= tds.current_min_sev_log_level) or (_log_type != tds.LOG_TYPE_DEBUG):
+
+        # log message in DEBUG format
+        _out_rec = ("%s|%s|%s|%s|%s|%s|%s|%s|%s"
+                    % ((calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, _msg)))
+        try:
+            tds.eelf_debug_fd.write('%s|%s\n' % (t_out, str(_out_rec)))
+        except Exception as e:
+            stdout_logger(str(_out_rec))
+
+    return True
+
+# # # # # # # # # # # # #
+# fx: stdout_logger
+# # # # # # # # # # # # #
+
+
+def stdout_logger(_msg):
+    """
+    Log info/errors to stdout.  This is done:
+      - for critical runtime issues
+
+    :Parameters:
+      _msg
+         message to print
+    :Exceptions:
+      none
+    :Keywords:
+      log stdout
+    :Variables:
+    """
+
+    t_out = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S,%f")[:-3]
+    # calling_fx = inspect.stack()[1][3]
+
+    print('%s %s' % (t_out, _msg))
diff --git a/bin/mod/trapd_logging.py b/snmptrap/mod/trapd_logging.py
similarity index 100%
rename from bin/mod/trapd_logging.py
rename to snmptrap/mod/trapd_logging.py
diff --git a/bin/mod/trapd_runtime_pid.py b/snmptrap/mod/trapd_runtime_pid.py
similarity index 100%
rename from bin/mod/trapd_runtime_pid.py
rename to snmptrap/mod/trapd_runtime_pid.py
diff --git a/bin/mod/trapd_settings.py b/snmptrap/mod/trapd_settings.py
similarity index 100%
rename from bin/mod/trapd_settings.py
rename to snmptrap/mod/trapd_settings.py
diff --git a/bin/snmptrapd.py b/snmptrap/snmptrapd.py
similarity index 77%
rename from bin/snmptrapd.py
rename to snmptrap/snmptrapd.py
index 3765746..9cf828c 100644
--- a/bin/snmptrapd.py
+++ b/snmptrap/snmptrapd.py
@@ -73,8 +73,7 @@
 from trapd_exit import cleanup_and_exit
 from trapd_http_session import init_session_obj
 
-from trapd_file_utils import roll_all_logs, open_eelf_logs, roll_file, open_file, close_file
-from trapd_logging import ecomp_logger, stdout_logger
+from trapd_io import roll_all_logs, open_eelf_logs, roll_file, open_file, close_file, ecomp_logger, stdout_logger
 
 prog_name = os.path.basename(__file__)
 verbose = False
@@ -146,7 +145,18 @@
         msg = "error (re)loading CBS config - FATAL ERROR, exiting"
         stdout_logger(msg)
         cleanup_and_exit(1, tds.pid_file_name)
+    else:
+        current_runtime_config_file_name = tds.c_config['files.runtime_base_dir'] + \
+            "/tmp/current_config.json"
 
+        msg = "current config logged to : %s" % current_runtime_config_file_name
+        ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg)
+
+        with open(current_runtime_config_file_name, 'w') as outfile:
+            json.dump(tds.c_config, outfile)
+
+        # if here, config re-read successfully
+        return True
 
 # # # # # # # # # # # # #
 # fx: log_all_arriving_traps
@@ -624,181 +634,184 @@
 # Main  MAIN  Main  MAIN
 # # # # # # # # # # # # #
 # parse command line args
-parser = argparse.ArgumentParser(description='Post SNMP traps '
-                                             'to message bus')
-parser.add_argument('-v', action="store_true", dest="verbose",
-                    help="verbose logging")
-parser.add_argument('-?', action="store_true", dest="usage_requested",
-                    help="show command line use")
 
-# parse args
-args = parser.parse_args()
+if __name__ == "__main__":
 
-# set vars from args
-verbose = args.verbose
-usage_requested = args.usage_requested
-
-# if usage, just display and exit
-if usage_requested:
-    usage_err()
-
-# init vars
-tds.init()
-
-# Set initial startup hour for rolling logfile
-tds.last_hour = datetime.datetime.now().hour
-
-# get config binding service (CBS) values (either broker, or json file override)
-load_all_configs(0, 0)
-msg = "%s : %s version %s starting" % (
-    prog_name, tds.c_config['snmptrap.title'], tds.c_config['snmptrap.version'])
-stdout_logger(msg)
-
-# Avoid this unless needed for testing; it prints sensitive data to log
-#
-# msg = "Running config: "
-# stdout_logger(msg)
-# msg = json.dumps(c_config, sort_keys=False, indent=4)
-# stdout_logger(msg)
-
-# open various ecomp logs
-open_eelf_logs()
-
-# bump up logging level if overridden at command line
-if verbose:
-    msg = "WARNING:  '-v' argument present.  All messages will be logged.  This can slow things down, use only when needed."
-    tds.minimum_severity_to_log = 0
+    parser = argparse.ArgumentParser(description='Post SNMP traps '
+                                                 'to message bus')
+    parser.add_argument('-v', action="store_true", dest="verbose",
+                        help="verbose logging")
+    parser.add_argument('-?', action="store_true", dest="usage_requested",
+                        help="show command line use")
+    
+    # parse args
+    args = parser.parse_args()
+    
+    # set vars from args
+    verbose = args.verbose
+    usage_requested = args.usage_requested
+    
+    # if usage, just display and exit
+    if usage_requested:
+        usage_err()
+    
+    # init vars
+    tds.init()
+    
+    # Set initial startup hour for rolling logfile
+    tds.last_hour = datetime.datetime.now().hour
+    
+    # get config binding service (CBS) values (either broker, or json file override)
+    load_all_configs(0, 0)
+    msg = "%s : %s version %s starting" % (
+        prog_name, tds.c_config['snmptrap.title'], tds.c_config['snmptrap.version'])
     stdout_logger(msg)
-
-# name and open arriving trap log
-tds.arriving_traps_filename = tds.c_config['files.runtime_base_dir'] + "/" + \
-    tds.c_config['files.log_dir'] + "/" + \
-    (tds.c_config['files.arriving_traps_log'])
-tds.arriving_traps_fd = open_file(tds.arriving_traps_filename)
-msg = ("arriving traps logged to: %s" % tds.arriving_traps_filename)
-stdout_logger(msg)
-ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg)
-
-# name and open json trap log
-tds.json_traps_filename = tds.c_config['files.runtime_base_dir'] + "/" + tds.c_config['files.log_dir'] + "/" + "DMAAP_" + (
-    tds.c_config['streams_publishes']['sec_fault_unsecure']['dmaap_info']['topic_url'].split('/')[-1]) + ".json"
-tds.json_traps_fd = open_file(tds.json_traps_filename)
-msg = ("published traps logged to: %s" % tds.json_traps_filename)
-stdout_logger(msg)
-ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg)
-
-# setup signal handling for config reload
-signal.signal(signal.SIGUSR1, load_all_configs)
-
-# save current PID for future/external reference
-tds.pid_file_name = tds.c_config['files.runtime_base_dir'] + \
-    '/' + tds.c_config['files.pid_dir'] + '/' + prog_name + ".pid"
-msg = "Runtime PID file: %s" % tds.pid_file_name
-ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg)
-rc = save_pid(tds.pid_file_name)
-
-# Get the event loop for this thread
-loop = asyncio.get_event_loop()
-
-# Create SNMP engine with autogenernated engineID pre-bound
-# to socket transport dispatcher
-snmp_engine = engine.SnmpEngine()
-
-# # # # # # # # # # # #
-# Transport setup
-# # # # # # # # # # # #
-
-# UDP over IPv4
-# FIXME:  add check for presense of ipv4_interface prior to attempting add OR just put entire thing in try/except clause
-try:
-    ipv4_interface = tds.c_config['protocols.ipv4_interface']
-    ipv4_port = tds.c_config['protocols.ipv4_port']
-
-    try:
-        config.addTransport(
-            snmp_engine,
-            udp.domainName + (1,),
-            udp.UdpTransport().openServerMode(
-                (ipv4_interface, ipv4_port))
-        )
-    except Exception as e:
-        msg = "Unable to bind to %s:%s - %s" % (
-            ipv4_interface, ipv4_port, str(e))
-        ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg)
+    
+    # Avoid this unless needed for testing; it prints sensitive data to log
+    #
+    # msg = "Running config: "
+    # stdout_logger(msg)
+    # msg = json.dumps(c_config, sort_keys=False, indent=4)
+    # stdout_logger(msg)
+    
+    # open various ecomp logs
+    open_eelf_logs()
+    
+    # bump up logging level if overridden at command line
+    if verbose:
+        msg = "WARNING:  '-v' argument present.  All diagnostic messages will be logged.  This can slow things down, use only when needed."
+        tds.minimum_severity_to_log = 0
         stdout_logger(msg)
-        cleanup_and_exit(1, tds.pid_file_name)
-
-except Exception as e:
-    msg = "IPv4 interface and/or port not specified in config - not listening for IPv4 traps"
+    
+    # name and open arriving trap log
+    tds.arriving_traps_filename = tds.c_config['files.runtime_base_dir'] + "/" + \
+        tds.c_config['files.log_dir'] + "/" + \
+        (tds.c_config['files.arriving_traps_log'])
+    tds.arriving_traps_fd = open_file(tds.arriving_traps_filename)
+    msg = ("arriving traps logged to: %s" % tds.arriving_traps_filename)
     stdout_logger(msg)
-    ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_WARN, tds.CODE_GENERAL, msg)
-
-
-# UDP over IPv4, second listening interface/port example if you don't want to listen on all
-# config.addTransport(
-#     snmp_engine,
-#     udp.domainName + (2,),
-#     udp.UdpTransport().openServerMode(('127.0.0.1', 2162))
-# )
-
-
-# UDP over IPv6
-# FIXME:  add check for presense of ipv6_interface prior to attempting add OR just put entire thing in try/except clause
-try:
-    ipv6_interface = tds.c_config['protocols.ipv6_interface']
-    ipv6_port = tds.c_config['protocols.ipv6_port']
-
+    ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg)
+    
+    # name and open json trap log
+    tds.json_traps_filename = tds.c_config['files.runtime_base_dir'] + "/" + tds.c_config['files.log_dir'] + "/" + "DMAAP_" + (
+        tds.c_config['streams_publishes']['sec_fault_unsecure']['dmaap_info']['topic_url'].split('/')[-1]) + ".json"
+    tds.json_traps_fd = open_file(tds.json_traps_filename)
+    msg = ("published traps logged to: %s" % tds.json_traps_filename)
+    stdout_logger(msg)
+    ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg)
+    
+    # setup signal handling for config reload
+    signal.signal(signal.SIGUSR1, load_all_configs)
+    
+    # save current PID for future/external reference
+    tds.pid_file_name = tds.c_config['files.runtime_base_dir'] + \
+        '/' + tds.c_config['files.pid_dir'] + '/' + prog_name + ".pid"
+    msg = "Runtime PID file: %s" % tds.pid_file_name
+    ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg)
+    rc = save_pid(tds.pid_file_name)
+    
+    # Get the event loop for this thread
+    loop = asyncio.get_event_loop()
+    
+    # Create SNMP engine with autogenernated engineID pre-bound
+    # to socket transport dispatcher
+    snmp_engine = engine.SnmpEngine()
+    
+    # # # # # # # # # # # #
+    # Transport setup
+    # # # # # # # # # # # #
+    
+    # UDP over IPv4
+    # FIXME:  add check for presense of ipv4_interface prior to attempting add OR just put entire thing in try/except clause
     try:
-        config.addTransport(
-            snmp_engine,
-            udp6.domainName,
-            udp6.Udp6Transport().openServerMode(
-                (ipv6_interface, ipv6_port))
-        )
+        ipv4_interface = tds.c_config['protocols.ipv4_interface']
+        ipv4_port = tds.c_config['protocols.ipv4_port']
+    
+        try:
+            config.addTransport(
+                snmp_engine,
+                udp.domainName + (1,),
+                udp.UdpTransport().openServerMode(
+                    (ipv4_interface, ipv4_port))
+            )
+        except Exception as e:
+            msg = "Unable to bind to %s:%s - %s" % (
+                ipv4_interface, ipv4_port, str(e))
+            ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg)
+            stdout_logger(msg)
+            cleanup_and_exit(1, tds.pid_file_name)
+    
     except Exception as e:
-        msg = "Unable to bind to %s:%s - %s" % (
-            ipv6_interface, ipv6_port, str(e))
+        msg = "IPv4 interface and/or port not specified in config - not listening for IPv4 traps"
         stdout_logger(msg)
-        ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg)
+        ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_WARN, tds.CODE_GENERAL, msg)
+    
+    
+    # UDP over IPv4, second listening interface/port example if you don't want to listen on all
+    # config.addTransport(
+    #     snmp_engine,
+    #     udp.domainName + (2,),
+    #     udp.UdpTransport().openServerMode(('127.0.0.1', 2162))
+    # )
+    
+    
+    # UDP over IPv6
+    # FIXME:  add check for presense of ipv6_interface prior to attempting add OR just put entire thing in try/except clause
+    try:
+        ipv6_interface = tds.c_config['protocols.ipv6_interface']
+        ipv6_port = tds.c_config['protocols.ipv6_port']
+    
+        try:
+            config.addTransport(
+                snmp_engine,
+                udp6.domainName,
+                udp6.Udp6Transport().openServerMode(
+                    (ipv6_interface, ipv6_port))
+            )
+        except Exception as e:
+            msg = "Unable to bind to %s:%s - %s" % (
+                ipv6_interface, ipv6_port, str(e))
+            stdout_logger(msg)
+            ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg)
+            cleanup_and_exit(1, tds.pid_file_name)
+    
+    except Exception as e:
+        msg = "IPv6 interface and/or port not specified in config - not listening for IPv6 traps"
+        stdout_logger(msg)
+        ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_WARN, tds.CODE_GENERAL, msg)
+    
+    
+    # # # # # # # # # # # #
+    # SNMPv1/2c setup
+    # # # # # # # # # # # #
+    
+    # SecurityName <-> CommunityName mapping
+    #     to restrict trap reception to only those with specific community
+    #     strings
+    config.addV1System(snmp_engine, 'my-area', 'public')
+    
+    # register comm_string_rewrite_observer for message arrival
+    snmp_engine.observer.registerObserver(
+        comm_string_rewrite_observer,
+        'rfc2576.processIncomingMsg:writable'
+    )
+    
+    # register snmp_engine_observer_cb for message arrival
+    snmp_engine.observer.registerObserver(
+        snmp_engine_observer_cb,
+        'rfc3412.receiveMessage:request',
+        'rfc3412.returnResponsePdu',
+    )
+    
+    # Register SNMP Application at the SNMP engine
+    ntfrcv.NotificationReceiver(snmp_engine, notif_receiver_cb)
+    
+    snmp_engine.transportDispatcher.jobStarted(1)  # loop forever
+    
+    # Run I/O dispatcher which will receive traps
+    try:
+        snmp_engine.transportDispatcher.runDispatcher()
+    except Exception as e:
+        snmp_engine.observer.unregisterObserver()
+        snmp_engine.transportDispatcher.closeDispatcher()
         cleanup_and_exit(1, tds.pid_file_name)
-
-except Exception as e:
-    msg = "IPv6 interface and/or port not specified in config - not listening for IPv6 traps"
-    stdout_logger(msg)
-    ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_WARN, tds.CODE_GENERAL, msg)
-
-
-# # # # # # # # # # # #
-# SNMPv1/2c setup
-# # # # # # # # # # # #
-
-# SecurityName <-> CommunityName mapping
-#     to restrict trap reception to only those with specific community
-#     strings
-config.addV1System(snmp_engine, 'my-area', 'public')
-
-# register comm_string_rewrite_observer for message arrival
-snmp_engine.observer.registerObserver(
-    comm_string_rewrite_observer,
-    'rfc2576.processIncomingMsg:writable'
-)
-
-# register snmp_engine_observer_cb for message arrival
-snmp_engine.observer.registerObserver(
-    snmp_engine_observer_cb,
-    'rfc3412.receiveMessage:request',
-    'rfc3412.returnResponsePdu',
-)
-
-# Register SNMP Application at the SNMP engine
-ntfrcv.NotificationReceiver(snmp_engine, notif_receiver_cb)
-
-snmp_engine.transportDispatcher.jobStarted(1)  # loop forever
-
-# Run I/O dispatcher which will receive traps
-try:
-    snmp_engine.transportDispatcher.runDispatcher()
-except Exception as e:
-    snmp_engine.observer.unregisterObserver()
-    snmp_engine.transportDispatcher.closeDispatcher()
-    cleanup_and_exit(1, tds.pid_file_name)
diff --git a/bin/snmptrapd.sh b/snmptrap/snmptrapd.sh
old mode 100755
new mode 100644
similarity index 100%
rename from bin/snmptrapd.sh
rename to snmptrap/snmptrapd.sh
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..1875bf6
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,21 @@
+# ================================================================================
+# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+
+# empty __init__.py so that pytest can add correct path to coverage report, -- per pytest
+# best practice guideline
diff --git a/tests/_test_trapd_get_cbs_config.py b/tests/_test_trapd_get_cbs_config.py
deleted file mode 100644
index 5fcfc2a..0000000
--- a/tests/_test_trapd_get_cbs_config.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import pytest
-import unittest
-import os
-from onap_dcae_cbs_docker_client.client import get_config
-from trapd_exit import cleanup_and_exit
-from trapd_logging import stdout_logger
-import trapd_get_cbs_config
- 
-class test_get_cbs_config(unittest.TestCase):
-    """
-    Test the trapd_get_cbs_config mod
-    """
- 
-    def test_cbs_env_present(self):
-        """
-        Test that CBS env variable exists and we can get config even
-        if CONSUL_HOST doesn't provide
-        """
-        os.environ.update(CONSUL_HOST='nosuchhost')
-        result = trapd_get_cbs_config.trapd_get_cbs_config()
-        compare = str(result).startswith("{'snmptrap': ")
-        self.assertEqual(compare, False)
- 
-    def test_cbs_fallback_env_present(self):
-        """
-        Test that CBS fallback env variable exists and we can get config
-        from fallback env var
-        """
-        os.environ.update(CBS_SIM_JSON='../etc/snmptrapd.json')
-        result = trapd_get_cbs_config.trapd_get_cbs_config()
-        compare = str(result).startswith("{'snmptrap': ")
-        self.assertEqual(compare, False)
- 
-    def test_cbs_fallback_env_not_present(self):
-        """
-        Test that CBS fallback env variable does not exists fails
-        """
-        os.environ.update(CBS_SIM_JSON='../etc/no_such_file.json')
-        result = trapd_get_cbs_config.trapd_get_cbs_config()
-        compare = str(result).startswith("{'snmptrap': ")
-        self.assertEqual(compare, False)
- 
-if __name__ == '__main__':
-    unittest.main()
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..d78ed5e
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,12 @@
+import pytest
+
+@pytest.fixture
+
+def test_var(_var_name):
+
+    try:
+        _var_name
+    except NameError:
+        return False
+    else:
+        return True
diff --git a/tests/setup.py b/tests/snmp.setup.py
similarity index 100%
rename from tests/setup.py
rename to tests/snmp.setup.py
diff --git a/tests/test_snmptrapd.py b/tests/test_snmptrapd.py
index 2f1783c..2cc11d7 100644
--- a/tests/test_snmptrapd.py
+++ b/tests/test_snmptrapd.py
@@ -1,46 +1,88 @@
+import os
 import pytest
 import unittest
+import snmptrapd
+import datetime
+
+import trapd_settings as tds
+import trapd_http_session
 import trapd_runtime_pid
- 
-class test_save_pid(unittest.TestCase):
+import trapd_io
+import trapd_logging
+import trapd_get_cbs_config
+
+class test_snmptrapd(unittest.TestCase):
     """
     Test the save_pid mod
     """
  
-    def test_correct_usage(self):
+    def test_usage_err(self):
         """
-        Test that attempt to create pid file in standard location works
+        Test usage error
         """
-        result = trapd_runtime_pid.save_pid('/tmp/snmptrap_test_pid_file')
+
+        with pytest.raises(SystemExit) as pytest_wrapped_sys_exit:
+            result = snmptrapd.usage_err()
+            assert pytest_wrapped_sys_exit.type == SystemExit
+            assert pytest_wrapped_sys_exit.value.code == 1
+
+ 
+    def test_load_all_configs(self):
+        """
+        Test load of all configs
+        """
+
+        # init vars
+        tds.init()
+
+        # request load of CBS data
+        os.environ.update(CBS_SIM_JSON='/opt/app/snmptrap/etc/snmptrapd.json')
+        result = trapd_get_cbs_config.get_cbs_config()
         self.assertEqual(result, True)
- 
-    def test_missing_directory(self):
-        """
-        Test that attempt to create pid file in missing dir fails
-        """
-        result = trapd_runtime_pid.save_pid('/bogus/directory/for/snmptrap_test_pid_file')
-        self.assertEqual(result, False)
- 
-class test_rm_pid(unittest.TestCase):
-    """
-    Test the rm_pid mod
-    """
- 
-    def test_correct_usage(self):
-        """
-        Test that attempt to remove pid file in standard location works
-        """
-        # must create it before removing it
-        result = trapd_runtime_pid.save_pid('/tmp/snmptrap_test_pid_file')
-        result = trapd_runtime_pid.rm_pid('/tmp/snmptrap_test_pid_file')
+
+        # request load of CBS data
+        result = snmptrapd.load_all_configs(0, 1)
         self.assertEqual(result, True)
- 
-    def test_missing_file(self):
+
+    def test_log_all_arriving_traps(self):
         """
-        Test that attempt to rm non-existent pid file fails
+        Test logging of traps
         """
-        result = trapd_runtime_pid.rm_pid('/tmp/snmptrap_test_pid_file_9999')
-        self.assertEqual(result, False)
- 
+
+        # init vars
+        tds.init()
+
+        # request load of CBS data
+        os.environ.update(CBS_SIM_JSON='/opt/app/snmptrap/etc/snmptrapd.json')
+        result = trapd_get_cbs_config.get_cbs_config()
+
+        # set last day to current
+        tds.last_day = datetime.datetime.now().day
+
+        # trap dict for logging
+        tds.trap_dict = {'uuid': '06f6e91c-3236-11e8-9953-005056865aac', 'agent address': '1.2.3.4', 'agent name': 'test-agent.nodomain.com', 'cambria.partition': 'test-agent.nodomain.com', 'community': '', 'community len': 0, 'epoch_serno': 15222068260000, 'protocol version': 'v2c', 'time received': 1522206826.2938566, 'trap category': 'ONAP-COLLECTOR-SNMPTRAP', 'sysUptime': '218567736', 'notify OID': '1.3.6.1.4.1.9999.9.9.999', 'notify OID len': 10}
+
+        # open eelf logs
+        trapd_io.open_eelf_logs()
+
+        # open trap logs
+        tds.arriving_traps_filename = tds.c_config['files.runtime_base_dir'] + "/" + \
+            tds.c_config['files.log_dir'] + "/" + \
+            (tds.c_config['files.arriving_traps_log'])
+        tds.arriving_traps_fd = trapd_io.open_file(tds.arriving_traps_filename)
+
+        # name and open json trap log
+        tds.json_traps_filename = tds.c_config['files.runtime_base_dir'] + "/" + tds.c_config['files.log_dir'] + "/" + "DMAAP_" + (
+            tds.c_config['streams_publishes']['sec_fault_unsecure']['dmaap_info']['topic_url'].split('/')[-1]) + ".json"
+        tds.json_traps_fd = trapd_io.open_file(tds.json_traps_filename)
+        msg = ("published traps logged to: %s" % tds.json_traps_filename)
+        trapd_io.stdout_logger(msg)
+        trapd_logging.ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg)
+
+        # don't open files, but try to log - should raise exception
+        with pytest.raises(Exception) as pytest_wrapped_exception:
+            result = snmptrapd.log_all_arriving_traps()
+            assert pytest_wrapped_exception.type == AttributeError
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/test_trapd_get_cbs_config.py b/tests/test_trapd_get_cbs_config.py
new file mode 100644
index 0000000..415c951
--- /dev/null
+++ b/tests/test_trapd_get_cbs_config.py
@@ -0,0 +1,61 @@
+import pytest
+import unittest
+import os
+
+from onap_dcae_cbs_docker_client.client import get_config
+from trapd_exit import cleanup_and_exit
+from trapd_io import stdout_logger, ecomp_logger
+import trapd_settings as tds
+import trapd_get_cbs_config
+ 
+class test_get_cbs_config(unittest.TestCase):
+    """
+    Test the trapd_get_cbs_config mod
+    """
+ 
+    def test_cbs_env_present(self):
+        """
+        Test that CBS env variable exists and we can get config even
+        if CONSUL_HOST doesn't provide
+        """
+        os.environ.update(CONSUL_HOST='nosuchhost')
+        # result = trapd_get_cbs_config.get_cbs_config()
+        # print("result: %s" % result)
+        # compare = str(result).startswith("{'snmptrap': ")
+        # self.assertEqual(compare, False)
+
+        with pytest.raises(Exception) as pytest_wrapped_sys_exit:
+            result = trapd_get_cbs_config.get_cbs_config()
+            assert pytest_wrapped_sys_exit.type == SystemExit
+            # assert pytest_wrapped_sys_exit.value.code == 1
+
+ 
+    def test_cbs_override_env_invalid(self):
+        """
+        """
+        os.environ.update(CBS_SIM_JSON='/opt/app/snmptrap/etc/nosuchfile.json')
+        # result = trapd_get_cbs_config.get_cbs_config()
+        # print("result: %s" % result)
+        # compare = str(result).startswith("{'snmptrap': ")
+        # self.assertEqual(compare, False)
+
+        with pytest.raises(SystemExit) as pytest_wrapped_sys_exit:
+            result = trapd_get_cbs_config.get_cbs_config()
+            assert pytest_wrapped_sys_exit.type == SystemExit
+            assert pytest_wrapped_sys_exit.value.code == 1
+
+ 
+    def test_cbs_fallback_env_present(self):
+        """
+        Test that CBS fallback env variable exists and we can get config
+        from fallback env var
+        """
+        os.environ.update(CBS_SIM_JSON='/opt/app/snmptrap/etc/snmptrapd.json')
+        result = trapd_get_cbs_config.get_cbs_config()
+        print("result: %s" % result)
+        # compare = str(result).startswith("{'snmptrap': ")
+        # self.assertEqual(compare, True)
+        self.assertEqual(result, True)
+ 
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_trapd_settings.py b/tests/test_trapd_settings.py
new file mode 100644
index 0000000..ab64426
--- /dev/null
+++ b/tests/test_trapd_settings.py
@@ -0,0 +1,73 @@
+import pytest
+import unittest
+import trapd_exit
+
+pid_file="/tmp/test_pid_file"
+pid_file_dne="/tmp/test_pid_file_NOT"
+
+import trapd_settings as tds
+from conftest import test_var
+
+class test_cleanup_and_exit(unittest.TestCase):
+    """
+    Test for presense of required vars
+    """
+ 
+
+    def test_nonexistent_dict(self):
+        """
+        Test nosuch var
+        """
+        tds.init()
+        try:
+            tds.no_such_var
+            result = True
+        except:
+            result = False
+
+        self.assertEqual(result, False)
+ 
+    def test_config_dict(self):
+        """
+        Test config dict
+        """
+        tds.init()
+        try:
+            tds.c_config
+            result = True
+        except:
+            result = False
+
+        self.assertEqual(result, True)
+ 
+    def test_dns_cache_ip_to_name(self):
+        """
+        Test dns cache name dict 
+        """
+
+        tds.init()
+        try:
+            tds.dns_cache_ip_to_name
+            result = True
+        except:
+            result = False
+
+        self.assertEqual(result, True)
+
+    def test_dns_cache_ip_expires(self):
+        """
+        Test dns cache ip expires dict 
+        """
+
+        tds.init()
+        try:
+            tds.dns_cache_ip_expires
+            result = True
+        except:
+            result = False
+
+        self.assertEqual(result, True)
+
+if __name__ == '__main__':
+    # tds.init()
+    unittest.main()
diff --git a/tests/tox.ini b/tests/tox.ini
deleted file mode 100644
index 3d8e842..0000000
--- a/tests/tox.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[tox]
-envlist = py36
- 
-[testenv]
-deps = coverage
-commands = coverage erase
- 
-[testenv:py36]
-deps = coverage pytest
-commands = coverage run ../bin/snmptrapd.py &
-           pytest test_trapd_exit.py  
-           pytest test_trapd_http_session.py  
-           pytest test_trapd_runtime_pid.py
-           ./test_snmptrapd_send_test_trap.py &
-           coverage report -m
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..4159d31
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,15 @@
+# content of: tox.ini , put in same dir as setup.py
+[tox]
+envlist = py27
+
+[testenv]
+deps=
+    -rrequirements.txt
+    pytest
+    coverage
+    pytest-cov
+setenv =
+    PYTHONPATH={toxinidir}
+recreate = True
+commands=
+    pytest --cov snmptrap --cov-report=xml --cov-report=term tests --verbose