4 # Client is authenticated with an API key and a secret
5 # The API key is a 64 chars string (digits and letters) that is passed to the request
6 # The secret is a 64 chars string that is used to sign the request
7 # The generated signature is a SHA256 hes digest
16 from myslice.configengine import ConfigEngine
17 from myslice.settings import logger
20 import sqlite3 as lite
24 config = ConfigEngine()
25 if config.activity and config.activity.apikey :
26 apikey = config.activity.apikey
28 # apikey will be necessary
31 if config.activity and config.activity.secret :
32 secret = config.activity.secret
34 # secret will be necessary
37 if config.activity and config.activity.server :
38 server = config.activity.server
41 server = "http://athos.ipv6.lip6.fr/activity/push/log"
43 def logWrite(request, action, message, objects = None):
46 logger.info("===============>> activity: no apikey")
49 logger.info("===============>> activity: no secret")
52 timestamp = time.mktime(datetime.datetime.today().timetuple())
53 ip = getClientIp(request)
55 "timestamp" : timestamp,
57 "host" : request.get_host(),
58 "referrer" : request.META.get('HTTP_REFERER'),
59 "user" : request.user.username,
63 "signature" : sign(secret, "%s%s%s%s" % (timestamp, ip, request.user, action)),
66 "resource_type" : None,
71 if objects is not None:
77 result = urllib2.urlopen(server, urllib.urlencode(log))
78 logger.info("===============>> activity: {} <{}> {}".format(action, request.user,message))
79 content = result.read()
81 #checking for not sent data and sending it (50% probability)
82 if random.randint(0,100) < 50:
85 except urllib2.URLError as e:
86 logger.error("===============>> activity: connection to {} impossible, could not log action".format(server))
87 logger.error(e.strerror)
89 dbfile = ''.join([os.path.dirname(os.path.abspath(__file__)), "/errors.db"])
92 conn = lite.connect(dbfile)
94 cur.execute("""INSERT INTO logs(log) values('%s')""" % json.dumps(log))
97 # this means that writing log into db also failed :(
98 # Last chance to preserve log is to send it to system syslog
99 # however there is no mechanism to pull it from this log - just manually.
100 logger.error('[activity] Error while inserting into sql db: %s' % str(e.args))
101 logger.error("[activity] data to send: '%s'" % json.dumps(log))
105 def log(request, action, message, objects = None):
106 # Create a new thread in Daemon mode to send the log entry
107 t = threading.Thread(target=logWrite, args=(request, action, message, objects))
111 def getClientIp(request):
113 x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
114 ip = x_forwarded_for.split(',')[0]
116 ip = request.META.get('REMOTE_ADDR')
120 # sign the request with the secret key
121 def sign(secret, message):
122 return hmac.new(secret, msg=message, digestmod=hashlib.sha256).hexdigest()
125 # sending the logs cached in sqlite database
128 """Checking local database for logs adn sending it to monitoring server"""
129 dbfile = ''.join([os.path.dirname(os.path.abspath(__file__)), "/errors.db"])
132 #trying to connect local db adn pull unsent logs
134 conn = lite.connect(dbfile)
136 cur.execute("SELECT rowid, log from logs")
137 notsent = cur.fetchall()
139 #trying to send unsent data from sqlite db
141 urllib2.urlopen(config.activity.server, urllib.urlencode(json.loads(row[1])))
142 #delete those who were sent
143 cur.execute("""DELETE FROM logs where rowid = %s""" % row[0] )
145 except urllib2.URLError as e:
146 # this is just to inform that DB is not working properly
147 logger.error('[activity] Error while sending stats')
148 logger.error(e.strerror)
150 except lite.Error, e:
151 #this need to be updated to store information via syslog
152 logger.error('[activity] Error while pulling from local sqlite3 db: %s' % str(e.args))
153 logger.error(e.strerror)