root / docs / design / logging-management-commands.rst @ b2376ba3
History | View | Annotate | Download (4.7 kB)
1 | b2376ba3 | Ilias Tsitsimpis | =================================================== |
---|---|---|---|
2 | b2376ba3 | Ilias Tsitsimpis | Logging mechanism for Synnefo's management commands |
3 | b2376ba3 | Ilias Tsitsimpis | =================================================== |
4 | b2376ba3 | Ilias Tsitsimpis | |
5 | b2376ba3 | Ilias Tsitsimpis | |
6 | b2376ba3 | Ilias Tsitsimpis | Abstract |
7 | b2376ba3 | Ilias Tsitsimpis | ======== |
8 | b2376ba3 | Ilias Tsitsimpis | |
9 | b2376ba3 | Ilias Tsitsimpis | Log all stdout and stderr output of every invocation of snf-manage, on unique |
10 | b2376ba3 | Ilias Tsitsimpis | filename under a given directory. |
11 | b2376ba3 | Ilias Tsitsimpis | |
12 | b2376ba3 | Ilias Tsitsimpis | |
13 | b2376ba3 | Ilias Tsitsimpis | Current state and shortcomings |
14 | b2376ba3 | Ilias Tsitsimpis | ============================== |
15 | b2376ba3 | Ilias Tsitsimpis | |
16 | b2376ba3 | Ilias Tsitsimpis | All Synnefo's management commands are written as custom django-admin commands. |
17 | b2376ba3 | Ilias Tsitsimpis | This means that every management command is in fact a class that extends |
18 | b2376ba3 | Ilias Tsitsimpis | Django's BaseCommand class. |
19 | b2376ba3 | Ilias Tsitsimpis | |
20 | b2376ba3 | Ilias Tsitsimpis | Django's *BaseCommand* provides the attributes ``self.stdout`` and |
21 | b2376ba3 | Ilias Tsitsimpis | ``self.stderr`` and Django's documentation encourages the users to use these |
22 | b2376ba3 | Ilias Tsitsimpis | attributes if they wish to write to the console. Django doesn't provide an |
23 | b2376ba3 | Ilias Tsitsimpis | option to write the output to files and the user has to implement this |
24 | b2376ba3 | Ilias Tsitsimpis | explicitly when implementing the ``handle`` method. |
25 | b2376ba3 | Ilias Tsitsimpis | |
26 | b2376ba3 | Ilias Tsitsimpis | We would like to extend the above mechanism to allow every ``snf-manage`` |
27 | b2376ba3 | Ilias Tsitsimpis | command to log all stdout and stderr output on a unique filename under a given |
28 | b2376ba3 | Ilias Tsitsimpis | directory. The implementation should change nothing in the way that users write |
29 | b2376ba3 | Ilias Tsitsimpis | management commands (only acceptable change is that the new commands may have |
30 | b2376ba3 | Ilias Tsitsimpis | to inherit a new class and not the *BaseCommand* one). This means that |
31 | b2376ba3 | Ilias Tsitsimpis | existing management commands should play out of the box and also that the |
32 | b2376ba3 | Ilias Tsitsimpis | logging mechanism will globally apply to all of them. |
33 | b2376ba3 | Ilias Tsitsimpis | |
34 | b2376ba3 | Ilias Tsitsimpis | |
35 | b2376ba3 | Ilias Tsitsimpis | Proposed changes |
36 | b2376ba3 | Ilias Tsitsimpis | ================ |
37 | b2376ba3 | Ilias Tsitsimpis | |
38 | b2376ba3 | Ilias Tsitsimpis | In this section we will try to explain the way that the new logging mechanism |
39 | b2376ba3 | Ilias Tsitsimpis | will be implemented as well as the reasons behind these decisions. |
40 | b2376ba3 | Ilias Tsitsimpis | |
41 | b2376ba3 | Ilias Tsitsimpis | As we previously saw, we want the logging mechanism to be global and to work |
42 | b2376ba3 | Ilias Tsitsimpis | for all the ``snf-manage`` commands without extra efford. This means that the |
43 | b2376ba3 | Ilias Tsitsimpis | management commands will continue to use the ``self.stdout`` and |
44 | b2376ba3 | Ilias Tsitsimpis | ``self.stderr`` attributes from *BaseCommand* class to provide console |
45 | b2376ba3 | Ilias Tsitsimpis | output. Therefor we have to provide our own ``self.stdout`` and ``self.stderr`` |
46 | b2376ba3 | Ilias Tsitsimpis | objects that will preserve the previous functionality and log to files at the |
47 | b2376ba3 | Ilias Tsitsimpis | same time. There are two ways to achieve that: |
48 | b2376ba3 | Ilias Tsitsimpis | |
49 | b2376ba3 | Ilias Tsitsimpis | Patch the Django's *BaseCommand* class and replace ``self.stdout`` and |
50 | b2376ba3 | Ilias Tsitsimpis | ``self.stderr`` attributes. |
51 | b2376ba3 | Ilias Tsitsimpis | |
52 | b2376ba3 | Ilias Tsitsimpis | This solution requires the minimum amount of changes to the management |
53 | b2376ba3 | Ilias Tsitsimpis | commands' code as they will use our patched version of *BaseCommand*. |
54 | b2376ba3 | Ilias Tsitsimpis | The downside is that we have to patch a library provided class. We are not |
55 | b2376ba3 | Ilias Tsitsimpis | encouraging these type of patches because it obfuscates the code (the |
56 | b2376ba3 | Ilias Tsitsimpis | programmer is expecting to use Django's *BaseCommand* class, not ours) |
57 | b2376ba3 | Ilias Tsitsimpis | and does not preserve compatiblity with other Django versions (if the |
58 | b2376ba3 | Ilias Tsitsimpis | implementation of Django's *BaseCommand* changes our patch will not |
59 | b2376ba3 | Ilias Tsitsimpis | work). |
60 | b2376ba3 | Ilias Tsitsimpis | |
61 | b2376ba3 | Ilias Tsitsimpis | Create a new class that extends Django's *BaseCommand*. |
62 | b2376ba3 | Ilias Tsitsimpis | |
63 | b2376ba3 | Ilias Tsitsimpis | The downside of this solution is that we have to change the existing code |
64 | b2376ba3 | Ilias Tsitsimpis | so all management commands will inherit our new class and not Django's |
65 | b2376ba3 | Ilias Tsitsimpis | *BaseCommand*. But we find this solution to be cleaner. |
66 | b2376ba3 | Ilias Tsitsimpis | |
67 | b2376ba3 | Ilias Tsitsimpis | For the above reasons we decided to go with the second option. |
68 | b2376ba3 | Ilias Tsitsimpis | |
69 | b2376ba3 | Ilias Tsitsimpis | |
70 | b2376ba3 | Ilias Tsitsimpis | Django's ``self.stdout`` and ``self.stderr`` are implemented as |
71 | b2376ba3 | Ilias Tsitsimpis | *OutputWrapper* objects. We will create our own class which will handle the |
72 | b2376ba3 | Ilias Tsitsimpis | file part of the logging and we will handle the console part to the original |
73 | b2376ba3 | Ilias Tsitsimpis | *OutputWrapper* object. We can't have used the ``logger`` libary as we want |
74 | b2376ba3 | Ilias Tsitsimpis | to preserve the functionality of Django's *OutputWrapper* (it uses style |
75 | b2376ba3 | Ilias Tsitsimpis | functions to pretty print the messages). |
76 | b2376ba3 | Ilias Tsitsimpis | |
77 | b2376ba3 | Ilias Tsitsimpis | Our new class has to be a **descriptor**. This is because *BaseCommand* doesn't |
78 | b2376ba3 | Ilias Tsitsimpis | initialize the ``stdout`` and ``stderr`` attributes at ``__init__`` but sets |
79 | b2376ba3 | Ilias Tsitsimpis | them only when it needs to (meaning inside the *execute* method). |
80 | b2376ba3 | Ilias Tsitsimpis | |
81 | b2376ba3 | Ilias Tsitsimpis | The above classes will be written in snf-django-lib package meaning that all |
82 | b2376ba3 | Ilias Tsitsimpis | the other packages will have a dependency in snf-django-lib. |
83 | b2376ba3 | Ilias Tsitsimpis | |
84 | b2376ba3 | Ilias Tsitsimpis | We will combine timestamp, command name and PID to form unique names, e.g.: |
85 | b2376ba3 | Ilias Tsitsimpis | 20140120113432-server-modify-4564, where "4564" was the PID. The timestamp will |
86 | b2376ba3 | Ilias Tsitsimpis | be first so that files will be chronologically sorted. |
87 | b2376ba3 | Ilias Tsitsimpis | |
88 | b2376ba3 | Ilias Tsitsimpis | |
89 | b2376ba3 | Ilias Tsitsimpis | Implementation details |
90 | b2376ba3 | Ilias Tsitsimpis | ====================== |
91 | b2376ba3 | Ilias Tsitsimpis | |
92 | b2376ba3 | Ilias Tsitsimpis | The implementation will follow the folowing steps: |
93 | b2376ba3 | Ilias Tsitsimpis | |
94 | b2376ba3 | Ilias Tsitsimpis | - Change current management commands to use ``self.stdout`` and ``self.stderr`` |
95 | b2376ba3 | Ilias Tsitsimpis | to provide console output instead of ``sys.stdout``, ``print`` or anything |
96 | b2376ba3 | Ilias Tsitsimpis | else. This change complies with Django's documentation. |
97 | b2376ba3 | Ilias Tsitsimpis | |
98 | b2376ba3 | Ilias Tsitsimpis | - Write a new class that will replace Django's *OutputWrapper*. |
99 | b2376ba3 | Ilias Tsitsimpis | |
100 | b2376ba3 | Ilias Tsitsimpis | - Write a new class (named **SynnefoBaseCommand**) that will extend Django's |
101 | b2376ba3 | Ilias Tsitsimpis | *BaseCommand* and will replace ``stdout`` and ``stderr`` attributes. |
102 | b2376ba3 | Ilias Tsitsimpis | |
103 | b2376ba3 | Ilias Tsitsimpis | - Change all management commands to inherit this new class |
104 | b2376ba3 | Ilias Tsitsimpis | **SynnefoBaseCommand**. |
105 | b2376ba3 | Ilias Tsitsimpis | |
106 | b2376ba3 | Ilias Tsitsimpis | - Update package dependencies. |
107 | b2376ba3 | Ilias Tsitsimpis | |
108 | b2376ba3 | Ilias Tsitsimpis | - Add a new Synnefo setting to allow the user the change the directory where |
109 | b2376ba3 | Ilias Tsitsimpis | the output will be saved. |