소스 검색

Added a Counters class for bumping event counters.

Michael Hope 3 년 전
부모
커밋
460083fc1b
2개의 변경된 파일57개의 추가작업 그리고 20개의 파일을 삭제
  1. 31 20
      niche.py
  2. 26 0
      utils.py

+ 31 - 20
niche.py 파일 보기

@@ -44,7 +44,7 @@ urls = (
44 44
     r'/logout', 'logout',
45 45
     r'/newuser', 'newuser',
46 46
     r'/rss', 'rss',
47
-    r'/internal/gc', 'internal_gc',
47
+    r'/debug/counters', 'debug_counters',
48 48
 )
49 49
 
50 50
 ALLOWED_TAGS = """
@@ -86,6 +86,8 @@ DEFAULTS = [
86 86
             }),
87 87
     ]
88 88
 
89
+counters = utils.Counters()
90
+
89 91
 class Config(ConfigParser.RawConfigParser):
90 92
     def set_defaults(self, defaults):
91 93
         for section, items in defaults:
@@ -451,6 +453,7 @@ def check_password(got, user):
451 453
 def error(message, condition, target='/'):
452 454
     """Log an error if condition is true and bounce to somewhere."""
453 455
     if condition:
456
+        counters.bump('error')
454 457
         model.inform(message)
455 458
         redirect(target)
456 459
 
@@ -475,10 +478,13 @@ def render_links(where=None, span=None, vars={}, date_range=None):
475 478
 
476 479
 class index:
477 480
     def GET(self):
481
+        counters.bump(self)
478 482
         return render_links()
479 483
 
480 484
 class links:
481 485
     def GET(self, year, month, day):
486
+        counters.bump(self)
487
+
482 488
         def tidy(v, low, high):
483 489
             """Turn an optional parameter into a validated number"""
484 490
             if v:
@@ -539,6 +545,7 @@ class links:
539 545
 
540 546
 class link:
541 547
     def GET(self, id):
548
+        counters.bump(self)
542 549
         link = model.get_link(id)
543 550
         form = new_comment.form()
544 551
         return render.link(link, form, False)
@@ -566,6 +573,7 @@ class new_link:
566 573
         return render.new_link(self.form(), None)
567 574
 
568 575
     def POST(self):
576
+        counters.bump(self)
569 577
         self.authenticate()
570 578
 
571 579
         form = self.form()
@@ -604,6 +612,7 @@ class new_link:
604 612
 
605 613
 class hide_link:
606 614
     def GET(self, id):
615
+        counters.bump(self)
607 616
         link = model.get_link(id)
608 617
         need_admin(_('Admin needed to hide a link'))
609 618
 
@@ -615,6 +624,7 @@ class hide_link:
615 624
 
616 625
 class close_link:
617 626
     def GET(self, id):
627
+        counters.bump(self)
618 628
         link = model.get_link(id)
619 629
 
620 630
         need_admin(_('Admin needed to close a link'))
@@ -640,6 +650,7 @@ class new_comment:
640 650
         return link
641 651
 
642 652
     def POST(self, id):
653
+        counters.bump(self)
643 654
         link = self.check(id)
644 655
         form = self.form()
645 656
 
@@ -663,6 +674,7 @@ class new_comment:
663 674
 
664 675
 class delete_comment:
665 676
     def GET(self, id):
677
+        counters.bump(self)
666 678
         comment = model.get_comment(id)
667 679
 
668 680
         need_admin(_('Admin needed to delete a comment'))
@@ -673,6 +685,7 @@ class delete_comment:
673 685
 
674 686
 class like_comment:
675 687
     def GET(self, id):
688
+        counters.bump(self)
676 689
         require_feature('likes')
677 690
         authenticate(_("Login to like"))
678 691
         comment = model.get_comment(id)
@@ -685,16 +698,19 @@ class like_comment:
685 698
 
686 699
 class user:
687 700
     def GET(self, id):
701
+        counters.bump(self)
688 702
         user = first('user', 'username', id)
689 703
         return render.user(user)
690 704
 
691 705
 class user_links:
692 706
     def GET(self, id):
707
+        counters.bump(self)
693 708
         user = first('user', 'username', id)
694 709
         return render_links(where='userID=$id', vars={'id': user.userID})
695 710
 
696 711
 class user_comments:
697 712
     def GET(self, id):
713
+        counters.bump(self)
698 714
         user = first('user', 'username', id)
699 715
         comments = db.select('1_comments', where='userID=$id', order='timestamp DESC',
700 716
                              vars={'id': user.userID},
@@ -703,6 +719,7 @@ class user_comments:
703 719
 
704 720
 class checkout:
705 721
     def GET(self, name):
722
+        counters.bump(self)
706 723
         require_feature('checkout')
707 724
         user = model.get_user_by_name(name)
708 725
         need_user_or_admin(user.userID, _('Only the user can checkout their links'))
@@ -721,6 +738,7 @@ class login:
721 738
         return render.login(self.login())
722 739
 
723 740
     def POST(self):
741
+        counters.bump(self)
724 742
         form = self.login()
725 743
 
726 744
         if not form.validates():
@@ -729,6 +747,7 @@ class login:
729 747
         user = first_or_none('user', 'username', form.d.username)
730 748
 
731 749
         if not check_password(form.d.password, user):
750
+            counters.bump(self, 'fail')
732 751
             form.valid = False
733 752
             model.inform(_("Bad username or password"))
734 753
             return render.login(form)
@@ -736,10 +755,12 @@ class login:
736 755
         session.userID = user.userID
737 756
 
738 757
         model.inform(_("Logged in"))
758
+        counters.bump(self, 'ok')
739 759
         redirect('/')
740 760
 
741 761
 class logout:
742 762
     def GET(self):
763
+        counters.bump(self)
743 764
         session.userID = None
744 765
 
745 766
         model.inform(_("Logged out"))
@@ -768,6 +789,7 @@ class password:
768 789
         return render.password(self.form())
769 790
 
770 791
     def POST(self, name):
792
+        counters.bump(self)
771 793
         target = self.authenticate(name)
772 794
         form = self.form()
773 795
 
@@ -776,6 +798,7 @@ class password:
776 798
 
777 799
         if not model.is_admin():
778 800
             if not check_password(form.d.password, target):
801
+                counters.bump(self, 'bad_password')
779 802
                 form.note = _('Bad password')
780 803
                 return render.password(form)
781 804
 
@@ -809,6 +832,7 @@ class user_edit:
809 832
         return render.user_edit(target, form)
810 833
 
811 834
     def POST(self, username):
835
+        counters.bump(self)
812 836
         target = self.get_target(username)
813 837
         form = self.make_form(target)
814 838
 
@@ -831,34 +855,21 @@ class user_edit:
831 855
 
832 856
 class rss:
833 857
     def GET(self):
858
+        counters.bump(self)
834 859
         require_feature('rss')
835 860
         links = db.select('1_links', order='linkID DESC', limit=20)
836 861
         links = map_all('link', links)
837 862
         web.header('Content-Type', 'application/xml')
838 863
         return naked_render.rss(links, web.ctx.home)
839 864
 
840
-_last = None
841 865
 
842
-class internal_gc:
866
+class debug_counters:
843 867
     def GET(self):
868
+        counters.bump(self)
844 869
         need_admin('Only admins can access server status pages.')
845
-        gc.collect()
846
-        gc.collect()
847
-        now = collections.defaultdict(int)
848
-        for i in gc.get_objects():
849
-            now[type(i)] += 1
850
-
851
-        global _last
852
-        last = _last
853
-        _last = now
854
-
855
-        if last is None:
856
-            return naked_render.internal_gc('Initialised', [])
857
-        else:
858
-            diff = [(x, now[x] - last[x]) for x in now]
859
-            diff = [x for x in diff if x[-1] > 0]
860
-            diff.sort(key=lambda x: x[-1])
861
-            return naked_render.internal_gc('Differences', diff)
870
+        web.header('Content-Type', 'application/json')
871
+        return json.dumps(counters.get_snapshot())
872
+
862 873
 
863 874
 def main():
864 875
     server_type = config.get('general', 'server_type')

+ 26 - 0
utils.py 파일 보기

@@ -1,4 +1,30 @@
1
+import collections
2
+import copy
1 3
 import time
4
+import threading
5
+
6
+
7
+class Counters(object):
8
+    def __init__(self):
9
+        self.counters = collections.defaultdict(int)
10
+        self.lock = threading.Lock()
11
+        self.counters['id'] = id(self)
12
+
13
+    def bump(self, name, arg=None):
14
+        if not isinstance(name, str):
15
+            name = name.__class__.__name__
16
+            if '.' in name:
17
+                name = name[name.rindex('.')+1:]
18
+        if arg:
19
+            name = '%s/%s' % (name, arg)
20
+
21
+        with self.lock:
22
+            self.counters[name] += 1
23
+
24
+    def get_snapshot(self):
25
+        with self.lock:
26
+            return copy.copy(self.counters)
27
+
2 28
 
3 29
 def now():
4 30
     """Return the current time in the right epoch."""