Merge lp:~stub/launchpad/bug-354035 into lp:launchpad
- bug-354035
- Merge into devel
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~stub/launchpad/bug-354035 |
Merge into: | lp:launchpad |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~stub/launchpad/bug-354035 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Diogo Matsubara (community) | qa | Approve | |
Gavin Panella (community) | code | Approve | |
Review via email: mp+9419@code.launchpad.net |
Commit message
Description of the change
Stuart Bishop (stub) wrote : | # |
Gavin Panella (allenap) wrote : | # |
Hi stub,
Only a couple of minute comments. Looks good :)
Gavin.
> === modified file 'lib/canonical/
> --- lib/canonical/
> +++ lib/canonical/
> @@ -134,7 +134,7 @@
> def get_request_
> """Get the list of executed statements in the request.
>
> - The list is composed of (starttime, endtime, statement) tuples.
> + The list is composed of (starttime, endtime, db_id, statement) tuples.
> Times are given in milliseconds since the start of the request.
> """
> return getattr(_local, 'request_
> @@ -165,7 +165,11 @@
> # convert times to integer millisecond values
> starttime = int((starttime - request_starttime) * 1000)
> endtime = int((endtime - request_starttime) * 1000)
> - _local.
> + # A string containing no whitespace that lets us identify which Store
> + # is being used.
> + database_identifier = connection_
> + _local.
> + (starttime, endtime, database_
>
> # store the last executed statement as an attribute on the current
> # thread
> @@ -274,6 +278,8 @@
> # opinion on what uri is.
> # pylint: disable-msg=W0231
> self._uri = uri
> + # A unique name for this database connection.
> + self.name = uri.database
>
> def raw_connect(self):
> # Prevent database connections from the main thread if
> @@ -348,6 +354,9 @@
>
> class LaunchpadSessio
>
> + # A unique name for this database connection.
> + name = 'session'
> +
> def raw_connect(self):
> self._dsn = 'dbname=%s user=%s' % (config.
> config.
>
> === modified file 'lib/canonical/
> --- lib/canonical/
> +++ lib/canonical/
> @@ -167,9 +167,9 @@
> fp.write('%s=%s\n' % (urllib.quote(key, safe_chars),
> urllib.quote(value, safe_chars)))
> fp.write('\n')
> - for (start, end, statement) in self.db_statements:
> - fp.write('%05d-%05d %s\n' % (start, end,
> - _normalise_
> + for (start, end, database_id, statement) in self.db_statements:
> + fp.write(
> + start, end, database_id, _normalise_
> fp.write('\n')
> fp.write(
>
> @@ -206,9 +206,15 @@
> line = line.strip()
> if line == '':
> break
> - startend, statement = line.split(' ', 1)
> - start, end = startend.split('-')
> - statements.
> + preamble, statement = line.split(' ', 1)
> + star...
Gavin Panella (allenap) wrote : | # |
> start, end, db_id, statement = re.match(
> r'^(\d+
Or even:
start, end, db_id, statement = re.match(
Stuart Bishop (stub) wrote : | # |
On Wed, Jul 29, 2009 at 7:40 PM, Gavin
Panella<email address hidden> wrote:
> Review: Approve code
> Hi stub,
>
> Only a couple of minute comments. Looks good :)
I've taken all your suggestions on board. Thanks!
--
Stuart Bishop <email address hidden>
http://
Diogo Matsubara (matsubara) wrote : | # |
Hi Stuart,
thanks for subscribing me. I checked your branch and indeed the changes break oops-tools. I'm working on a fix that should be ready by Monday. I'm marking as needs fixing and will add a bug task for oops-tools to the bug report. Once I have the fix for oops-tools ready, it'll be ok to land this branch.
Thanks.
Diogo
Diogo Matsubara (matsubara) wrote : | # |
Hi Stuart,
I've updated oops-tools to cope with database_id on SQL statement logs. Feel free to land your branch. Thanks!
Preview Diff
1 | === modified file 'lib/canonical/launchpad/webapp/adapter.py' |
2 | --- lib/canonical/launchpad/webapp/adapter.py 2009-07-28 22:35:01 +0000 |
3 | +++ lib/canonical/launchpad/webapp/adapter.py 2009-07-29 11:37:51 +0000 |
4 | @@ -134,7 +134,7 @@ |
5 | def get_request_statements(): |
6 | """Get the list of executed statements in the request. |
7 | |
8 | - The list is composed of (starttime, endtime, statement) tuples. |
9 | + The list is composed of (starttime, endtime, db_id, statement) tuples. |
10 | Times are given in milliseconds since the start of the request. |
11 | """ |
12 | return getattr(_local, 'request_statements', []) |
13 | @@ -165,7 +165,11 @@ |
14 | # convert times to integer millisecond values |
15 | starttime = int((starttime - request_starttime) * 1000) |
16 | endtime = int((endtime - request_starttime) * 1000) |
17 | - _local.request_statements.append((starttime, endtime, statement)) |
18 | + # A string containing no whitespace that lets us identify which Store |
19 | + # is being used. |
20 | + database_identifier = connection_wrapper._database.name |
21 | + _local.request_statements.append( |
22 | + (starttime, endtime, database_identifier, statement)) |
23 | |
24 | # store the last executed statement as an attribute on the current |
25 | # thread |
26 | @@ -274,6 +278,8 @@ |
27 | # opinion on what uri is. |
28 | # pylint: disable-msg=W0231 |
29 | self._uri = uri |
30 | + # A unique name for this database connection. |
31 | + self.name = uri.database |
32 | |
33 | def raw_connect(self): |
34 | # Prevent database connections from the main thread if |
35 | @@ -348,6 +354,9 @@ |
36 | |
37 | class LaunchpadSessionDatabase(Postgres): |
38 | |
39 | + # A unique name for this database connection. |
40 | + name = 'session' |
41 | + |
42 | def raw_connect(self): |
43 | self._dsn = 'dbname=%s user=%s' % (config.launchpad_session.dbname, |
44 | config.launchpad_session.dbuser) |
45 | |
46 | === modified file 'lib/canonical/launchpad/webapp/errorlog.py' |
47 | --- lib/canonical/launchpad/webapp/errorlog.py 2009-07-23 05:02:47 +0000 |
48 | +++ lib/canonical/launchpad/webapp/errorlog.py 2009-07-29 11:37:51 +0000 |
49 | @@ -167,9 +167,9 @@ |
50 | fp.write('%s=%s\n' % (urllib.quote(key, safe_chars), |
51 | urllib.quote(value, safe_chars))) |
52 | fp.write('\n') |
53 | - for (start, end, statement) in self.db_statements: |
54 | - fp.write('%05d-%05d %s\n' % (start, end, |
55 | - _normalise_whitespace(statement))) |
56 | + for (start, end, database_id, statement) in self.db_statements: |
57 | + fp.write('%05d-%05d@%s %s\n' % ( |
58 | + start, end, database_id, _normalise_whitespace(statement))) |
59 | fp.write('\n') |
60 | fp.write(self.tb_text) |
61 | |
62 | @@ -206,9 +206,15 @@ |
63 | line = line.strip() |
64 | if line == '': |
65 | break |
66 | - startend, statement = line.split(' ', 1) |
67 | - start, end = startend.split('-') |
68 | - statements.append((int(start), int(end), statement)) |
69 | + preamble, statement = line.split(' ', 1) |
70 | + start, suffix = preamble.split('-', 1) |
71 | + try: |
72 | + end, db_id = suffix.split('@', 1) |
73 | + db_id = intern(database_id) # This string is repeated lots. |
74 | + except ValueError: |
75 | + end, db_id = suffix, None |
76 | + statements.append( |
77 | + (int(start), int(end), db_id, statement)) |
78 | |
79 | # The rest is traceback. |
80 | tb_text = ''.join(lines) |
81 | @@ -471,9 +477,10 @@ |
82 | |
83 | duration = get_request_duration() |
84 | |
85 | - statements = sorted((start, end, _safestr(statement)) |
86 | - for (start, end, statement) |
87 | - in get_request_statements()) |
88 | + statements = sorted( |
89 | + (start, end, _safestr(database_id), _safestr(statement)) |
90 | + for (start, end, database_id, statement) |
91 | + in get_request_statements()) |
92 | |
93 | oopsid, filename = self.newOopsId(now) |
94 | |
95 | |
96 | === modified file 'lib/canonical/launchpad/webapp/tests/test_errorlog.py' |
97 | --- lib/canonical/launchpad/webapp/tests/test_errorlog.py 2009-07-17 00:26:05 +0000 |
98 | +++ lib/canonical/launchpad/webapp/tests/test_errorlog.py 2009-07-29 11:05:49 +0000 |
99 | @@ -57,8 +57,8 @@ |
100 | 'pageid', 'traceback-text', 'username', 'url', 42, |
101 | [('name1', 'value1'), ('name2', 'value2'), |
102 | ('name1', 'value3')], |
103 | - [(1, 5, 'SELECT 1'), |
104 | - (5, 10, 'SELECT 2')]) |
105 | + [(1, 5, 'store_a', 'SELECT 1'), |
106 | + (5, 10, 'store_b', 'SELECT 2')]) |
107 | self.assertEqual(entry.id, 'id') |
108 | self.assertEqual(entry.type, 'exc-type') |
109 | self.assertEqual(entry.value, 'exc-value') |
110 | @@ -74,8 +74,12 @@ |
111 | self.assertEqual(entry.req_vars[1], ('name2', 'value2')) |
112 | self.assertEqual(entry.req_vars[2], ('name1', 'value3')) |
113 | self.assertEqual(len(entry.db_statements), 2) |
114 | - self.assertEqual(entry.db_statements[0], (1, 5, 'SELECT 1')) |
115 | - self.assertEqual(entry.db_statements[1], (5, 10, 'SELECT 2')) |
116 | + self.assertEqual( |
117 | + entry.db_statements[0], |
118 | + (1, 5, 'store_a', 'SELECT 1')) |
119 | + self.assertEqual( |
120 | + entry.db_statements[1], |
121 | + (5, 10, 'store_b', 'SELECT 2')) |
122 | |
123 | def test_write(self): |
124 | """Test ErrorReport.write()""" |
125 | @@ -88,8 +92,8 @@ |
126 | [('HTTP_USER_AGENT', 'Mozilla/5.0'), |
127 | ('HTTP_REFERER', 'http://localhost:9000/'), |
128 | ('name=foo', 'hello\nworld')], |
129 | - [(1, 5, 'SELECT 1'), |
130 | - (5, 10, 'SELECT\n2')]) |
131 | + [(1, 5, 'store_a', 'SELECT 1'), |
132 | + (5, 10,'store_b', 'SELECT\n2')]) |
133 | fp = StringIO.StringIO() |
134 | entry.write(fp) |
135 | self.assertEqual(fp.getvalue(), dedent("""\ |
136 | @@ -108,13 +112,60 @@ |
137 | HTTP_REFERER=http://localhost:9000/ |
138 | name%%3Dfoo=hello%%0Aworld |
139 | |
140 | - 00001-00005 SELECT 1 |
141 | - 00005-00010 SELECT 2 |
142 | + 00001-00005@store_a SELECT 1 |
143 | + 00005-00010@store_b SELECT 2 |
144 | |
145 | traceback-text""" % (versioninfo.branch_nick, versioninfo.revno))) |
146 | |
147 | def test_read(self): |
148 | - """Test ErrorReport.read()""" |
149 | + """Test ErrorReport.read().""" |
150 | + fp = StringIO.StringIO(dedent("""\ |
151 | + Oops-Id: OOPS-A0001 |
152 | + Exception-Type: NotFound |
153 | + Exception-Value: error message |
154 | + Date: 2005-04-01T00:00:00+00:00 |
155 | + Page-Id: IFoo:+foo-template |
156 | + User: Sample User |
157 | + URL: http://localhost:9000/foo |
158 | + Duration: 42 |
159 | + |
160 | + HTTP_USER_AGENT=Mozilla/5.0 |
161 | + HTTP_REFERER=http://localhost:9000/ |
162 | + name%3Dfoo=hello%0Aworld |
163 | + |
164 | + 00001-00005@store_a SELECT 1 |
165 | + 00005-00010@store_b SELECT 2 |
166 | + |
167 | + traceback-text""")) |
168 | + entry = ErrorReport.read(fp) |
169 | + self.assertEqual(entry.id, 'OOPS-A0001') |
170 | + self.assertEqual(entry.type, 'NotFound') |
171 | + self.assertEqual(entry.value, 'error message') |
172 | + # XXX jamesh 2005-11-30: |
173 | + # this should probably convert back to a datetime |
174 | + self.assertEqual(entry.time, datetime.datetime(2005, 4, 1)) |
175 | + self.assertEqual(entry.pageid, 'IFoo:+foo-template') |
176 | + self.assertEqual(entry.tb_text, 'traceback-text') |
177 | + self.assertEqual(entry.username, 'Sample User') |
178 | + self.assertEqual(entry.url, 'http://localhost:9000/foo') |
179 | + self.assertEqual(entry.duration, 42) |
180 | + self.assertEqual(len(entry.req_vars), 3) |
181 | + self.assertEqual(entry.req_vars[0], ('HTTP_USER_AGENT', |
182 | + 'Mozilla/5.0')) |
183 | + self.assertEqual(entry.req_vars[1], ('HTTP_REFERER', |
184 | + 'http://localhost:9000/')) |
185 | + self.assertEqual(entry.req_vars[2], ('name=foo', 'hello\nworld')) |
186 | + self.assertEqual(len(entry.db_statements), 2) |
187 | + self.assertEqual( |
188 | + entry.db_statements[0], |
189 | + (1, 5, 'store_a', 'SELECT 1')) |
190 | + self.assertEqual( |
191 | + entry.db_statements[1], |
192 | + (5, 10, 'store_b', 'SELECT 2')) |
193 | + |
194 | + |
195 | + def test_read_no_store_id(self): |
196 | + """Test ErrorReport.read() for old logs with no store_id.""" |
197 | fp = StringIO.StringIO(dedent("""\ |
198 | Oops-Id: OOPS-A0001 |
199 | Exception-Type: NotFound |
200 | @@ -152,8 +203,8 @@ |
201 | 'http://localhost:9000/')) |
202 | self.assertEqual(entry.req_vars[2], ('name=foo', 'hello\nworld')) |
203 | self.assertEqual(len(entry.db_statements), 2) |
204 | - self.assertEqual(entry.db_statements[0], (1, 5, 'SELECT 1')) |
205 | - self.assertEqual(entry.db_statements[1], (5, 10, 'SELECT 2')) |
206 | + self.assertEqual(entry.db_statements[0], (1, 5, None, 'SELECT 1')) |
207 | + self.assertEqual(entry.db_statements[1], (5, 10, None, 'SELECT 2')) |
208 | |
209 | |
210 | class TestErrorReportingUtility(unittest.TestCase): |
211 | @@ -422,7 +473,7 @@ |
212 | # Test ErrorReportingUtility.raising() with an XML-RPC request. |
213 | request = TestRequest() |
214 | directlyProvides(request, IXMLRPCRequest) |
215 | - request.getPositionalArguments = lambda : (1,2) |
216 | + request.getPositionalArguments = lambda: (1, 2) |
217 | utility = ErrorReportingUtility() |
218 | now = datetime.datetime(2006, 04, 01, 00, 30, 00, tzinfo=UTC) |
219 | try: |
220 | @@ -469,7 +520,6 @@ |
221 | utility.raising(sys.exc_info(), request, now=now) |
222 | self.assertEqual(request.oopsid, None) |
223 | |
224 | - |
225 | def test_raising_for_script(self): |
226 | """Test ErrorReportingUtility.raising with a ScriptRequest.""" |
227 | utility = ErrorReportingUtility() |
228 | @@ -753,7 +803,7 @@ |
229 | # logged will have OOPS reports generated for them. |
230 | error_message = self.factory.getUniqueString() |
231 | try: |
232 | - 1/0 |
233 | + ignored = 1/0 |
234 | except ZeroDivisionError: |
235 | self.logger.exception(error_message) |
236 | oops_report = self.error_utility.getLastOopsReport() |
Address Bug #354035
This branch adds an identifier for the Store being used to the SQL statement logs. At the moment, this will normally be something like 'launchpad- main-master' . launchpad is the config section in launchpad-lazr.conf being used for database configuration, 'main' is the Store realm, 'master' is the Store flavour. The format of the identifier may change in the future, but it should remain a simple string.
Care has been taken to ensure old format OOPS reports are still loaded. The Store identifier is None for these OOPS reports.
I expect this will break some of the external OOPS handling tools, so requesting a review from matsubara to help identify what this will break and what to do about it.
There were some minor drive by lint and code standard cleanups.