Skip to content
90 changes: 52 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,54 @@
Simple Python MQTT Data Logger
# Simple Python MQTT Data Logger

This software uses the Python logger to create a logfile
for all messages for all topics to which this MQTT client
has subscribed.

Note: by default it will only log changed messages. This is for sensors
that send out their state a regular intervals but that state doesn't change
The program is run from the command line

You can subscribe to multiple topics.


You need to provide the script with:

* List of topics to monitor
* broker name and port
* username and password if needed.
* base log directory and number of logs have defaults

You need to provide the script with:

List of topics to monitor
broker name and port
username and password if needed.
base log directory and number of logs have defaults
Valid command line Options:
--help <help>
-h <broker>
-b <broker>
-p <port>
-t <topic>
-q <QOS>
-v <verbose>
-d logging debug
-n <Client ID or Name>
-u Username
-P Password
-s <store all data>\
-l <log directory default= mlogs>
-r <number of records default=100>\
-f <number of log files default= unlimited"

Example Usage:

--help <help>
-h <broker>
-b <broker>
-p <port>
-t <topic>
-q <QOS>
-v <verbose>
-d logging debug
-n <Client ID or Name>
-u Username
-P Password
-s <store all data>\
-l <log directory default= mlogs>
-r <number of records default=100>\
-f <number of log files default= unlimited"
-j <JSON>


# Install dependencies

You need the paho mqtt library. Using pip3:

pip install paho-mqtt

# Example Usage:

You will always need to specify the broker name or IP address
and the topics to log
and the topics to log.

Note: you may not need to use the python prefix or may
need to use python3 mqtt_data_logger.py (Linux)
Expand All @@ -51,10 +62,14 @@ Specify broker and multiple topics
python mqtt_data_logger.py -b 192.168.1.157 -t sensors/# -t home/#


Log All Data:
Log All Data (plain text format):

python mqtt_data_logger.py b 192.168.1.157 -t sensors/# -s

Log All Data (JSON format):

python mqtt_data_logger.py b 192.168.1.157 -t sensors/# -s -j

Specify the client name used by the logger

python mqtt_data_logger.py b 192.168.1.157 -t sensors/# -n data-logger
Expand All @@ -63,24 +78,22 @@ Specify the log directory

python mqtt_data_logger.py b 192.168.1.157 -t sensors/# -l mylogs

---------
Logger Class
# Logger Class

The class is implemented in a module called m_logger.py (message logger).

To create an instance you need to supply three parameters:

The log directory- defaults to mlogs
Number of records to log per log- defaults to 5000
Number of logs. 0 for no limit.- defaults to 0
* The log directory- defaults to mlogs
* Number of records to log per log- defaults to 5000
* Number of logs. 0 for no limit.- defaults to 0

log=m_logger(log_dir="logs",log_recs=5000,number_logs=0):
log=m_logger(log_dir="logs",log_recs=5000,number_logs=0):

The logger creates the log files in the directory using the current date and time for the directory names.

The format is month-day-hour-minute e.g.


You can log data either in plain text format or JSON format.

To log data either in plain text then use the
Expand All @@ -95,17 +108,18 @@ Both method takes a single parameter containing the data to log as a string, lis

e.g.

log.log_data(data)
log.log_data(data)

or
log.log_json(data)

#The log file will contain the data as
#plain text or JSON encoded data strings
#each on a newline.
log.log_json(data)

The log file will contain the data as plain text or JSON encoded data strings each on a newline.

The logger will return True if successful and False if not.

To prevent loss of data in the case of computer failure the logs are continuously flushed to disk .

Read more about this application here:
Read more about this application here:

http://www.steves-internet-guide.com/simple-python-mqtt-data-logger/
8 changes: 5 additions & 3 deletions command.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
options["cname"]=""
options["topics"]=[("",0)]
options["storechangesonly"]=True
options["JSON"]=False
options["keepalive"]=60
options["loglevel"]="WARNING"
options["log_dir"]="mlogs"
Expand All @@ -28,10 +29,10 @@ def command_input(options={}):
valid_options=" --help <help> -h or -b <broker> -p <port>-t <topic> -q QOS -v <verbose> -h <help>\
-d logging debug -n Client ID or Name -u Username -P Password -s <store all data>\
-l <log directory default= mlogs> -r <number of records default=100>\
-f <number of log files default= unlimited"
-f <number of log files default= unlimited -j <JSON>"
print_options_flag=False
try:
opts, args = getopt.getopt(sys.argv[1:],"h:b:sdk:p:t:q:l:vn:u:P:l:r:f:")
opts, args = getopt.getopt(sys.argv[1:],"h:b:sdk:p:t:q:l:vn:u:P:l:r:f:j")
except getopt.GetoptError:
print (sys.argv[0],valid_options)
sys.exit(2)
Expand Down Expand Up @@ -68,7 +69,8 @@ def command_input(options={}):
options["log_records"]=int(arg)
elif opt =="-f":
options["number_logs"]=int(arg)

elif opt =="-j":
options["JSON"]=True

lqos=len(qos_in)
for i in range(len(topics_in)):
Expand Down
2 changes: 1 addition & 1 deletion mlogger.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def create_log_dir(self,log_dir):
using the timestamp for the name
"""
self.t=time.localtime(time.time())
self.time_stamp=(str(self.t[1])+"-"+str(self.t[2])+"-"+\
self.time_stamp=(str(self.t[0])+"-"+str(self.t[1])+"-"+str(self.t[2])+"-"+\
str(self.t[3])+"-"+str(self.t[4]))
logging.info("creating sub directory"+str(self.time_stamp))
try:
Expand Down
34 changes: 20 additions & 14 deletions mqtt-data-logger.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!c:\python34\python.exe
#!/usr/bin/env python
#!/usr/bin/env python3
#If Running in Windows use top line and edit according to your python
#location and version. If running on Linux delete the top line.
###demo code provided by Steve Cope at www.steves-internet-guide.com
Expand Down Expand Up @@ -112,18 +111,25 @@ def on_message(client,userdata, msg):
#print("message received")

def message_handler(client,msg,topic):
data=dict()

tnow=time.localtime(time.time())
#m=time.asctime(tnow)+" "+topic+" "+msg
try:
msg=json.loads(msg)#convert to Javascript before saving
#print("json data")
except:
pass
#print("not already json")
data["time"]=tnow
data["topic"]=topic
data["message"]=msg

if options["JSON"]:
data=dict()
try:
msg=json.loads(msg)#convert to Javascript before saving
#print("json data")
except:
pass
#print("not already json")
data["time"]=tnow
data["topic"]=topic
data["message"]=msg
#print("Logging JSON format")
else:
data=time.asctime(tnow)+" "+topic+" "+msg+"\n"
#print("Logging plain text")

if command.options["storechangesonly"]:
if has_changed(client,topic,msg):
client.q.put(data) #put messages on queue
Expand Down Expand Up @@ -191,7 +197,7 @@ def log_worker():
client.sub_topics=options["topics"]
client.broker=options["broker"]
client.port=options["port"]
options["JSON"]=True #currently only supports JSON

if options["JSON"]:
print("Logging JSON format")
else:
Expand Down