1/*
2  Copyright (C) 2000-2005 SKYRIX Software AG
3
4  This file is part of SOPE.
5
6  SOPE is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License as published by the
8  Free Software Foundation; either version 2, or (at your option) any
9  later version.
10
11  SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12  WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14  License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with SOPE; see the file COPYING.  If not, write to the
18  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19  02111-1307, USA.
20*/
21
22#include <NGObjWeb/WODirectAction.h>
23#include <NGObjWeb/WOApplication.h>
24#include <NGObjWeb/WOResourceManager.h>
25#include <NGObjWeb/WOContext.h>
26#include <NGObjWeb/WORequest.h>
27#include <NGObjWeb/WOResponse.h>
28#include <NGObjWeb/WOSession.h>
29#include <NGObjWeb/WOStatisticsStore.h>
30#include "common.h"
31
32@interface WOApplication(MemoryStatistics)
33
34- (NSDictionary *)memoryStatistics;
35
36@end
37
38@implementation WOApplication(MemoryStatistics)
39
40- (NSDictionary *)memoryStatistics {
41#ifdef __linux__
42  FILE     *f;
43  char     buf[4096];
44  char     fname[256];
45  unsigned len;
46
47  sprintf(fname, "/proc/%d/status", getpid());
48  if ((f = fopen(fname, "r"))) {
49    id           d = nil;
50    NSString     *s;
51    NSEnumerator *lines;
52
53    len = fread(buf, 1, sizeof(buf) - 1, f);
54    fclose(f);
55    buf[len] = '\0';
56
57    s = [NSString stringWithCString:buf];
58    lines = [[s componentsSeparatedByString:@"\n"] objectEnumerator];
59    while ((s = [lines nextObject])) {
60      NSString *key;
61      NSRange rng;
62
63      rng = [s rangeOfString:@":"];
64      if (rng.length <= 0)
65        continue;
66
67      key = [s substringToIndex:rng.location];
68
69      if ([key hasPrefix:@"Vm"]) {
70        const char *cstr;
71        id value;
72
73        cstr = [s cString];
74        while (*cstr != '\0' && *cstr != ':') cstr++;
75        if (*cstr == '\0') continue;
76        cstr++;
77        while (*cstr != '\0' && isspace(*cstr)) cstr++;
78        value = [NSString stringWithCString:cstr];
79
80        if ([value hasSuffix:@" kB"]) {
81          value = [value substringToIndex:[value length] - 3];
82          value = [NSNumber numberWithInt:[value intValue] * 1024];
83        }
84
85        if (d == nil)
86	  d = [NSMutableDictionary dictionaryWithCapacity:16];
87        [(NSMutableDictionary *)d setObject:value forKey:key];
88      }
89    }
90    return d;
91  }
92#endif
93  return nil;
94}
95
96@end /* WOApplication(MemoryStatistics) */
97
98@implementation WODirectAction(WOStats)
99
100- (id<WOActionResults>)WOStatsAction {
101  WOApplication *app;
102  WOResponse   *response;
103  NSDictionary *stats;
104  NSString     *xslPath;
105  NSArray      *languages;
106  static NSDictionary *keyToDataType = nil;
107
108  if (keyToDataType == nil) {
109    keyToDataType =
110      [[NSDictionary alloc] initWithObjectsAndKeys:
111                                  @"number", @"averageDuration",
112                                  @"number", @"maximumDuration",
113                                  @"number", @"minimumDuration",
114                                  @"number", @"totalDuration",
115                                  @"number", @"instanceUptime",
116                                  @"number", @"instanceUptimeInHours",
117                                  @"number", @"instanceLoad",
118                                  @"number", @"pageResponseCount",
119                                  @"number", @"numberOfZippedResponses",
120                                  @"number", @"totalResponseCount",
121                                  @"number", @"pageFrequency",
122                                  @"number", @"pageDeliveryVolumne",
123                                  @"number", @"responseFrequency",
124                                  @"number", @"relativeTimeConsumption",
125                                  @"number", @"averageResponseSize",
126                                  @"number", @"totalResponseSize",
127                                  @"number", @"totalZippedSize",
128                                  @"number", @"smallestResponseSize",
129                                  @"number", @"largestResponseSize",
130                                  @"number", @"VmData",
131                                  @"number", @"VmExe",
132                                  @"number", @"VmRSS",
133                                  @"number", @"VmLib",
134                                  @"number", @"VmStk",
135                                  @"number", @"VmSize",
136                                  @"number", @"VmLck",
137                                  nil];
138  }
139
140  app = [WOApplication application];
141
142  xslPath = [[NSUserDefaults standardUserDefaults]
143                             stringForKey:@"WOStatsStylesheetName"];
144  languages = [[self context] resourceLookupLanguages];
145  xslPath   = [[app resourceManager] urlForResourceNamed:xslPath
146                                     inFramework:nil
147                                     languages:languages
148                                     request:[self request]];
149  if ([xslPath hasPrefix:@"/missingresource"])
150    xslPath = nil;
151
152  response = [WOResponse responseWithRequest:[self request]];
153  [response setContentEncoding:NSUTF8StringEncoding];
154  [response setHeader:@"text/xml; charset=utf-8" forKey:@"content-type"];
155
156  stats = [[app statisticsStore] statistics];
157
158  [response appendContentString:@"<?xml version='1.0'?>\n"];
159  if ([xslPath length] > 0) {
160    [response appendContentString:@"<?xml-stylesheet type='text/xsl' href='"];
161    [response appendContentString:xslPath];
162    [response appendContentString:@"'?>"];
163  }
164
165  [response appendContentString:@"<application name='"];
166  [response appendContentString:[app name]];
167  [response appendContentString:@"'"];
168  [response appendContentString:
169              [NSString stringWithFormat:@" pid='%d'", getpid()]];
170  [response appendContentString:
171              @" xmlns:dt='urn:schemas-microsoft-com:datatypes'>\n"];
172
173  {
174    NSEnumerator *e;
175    NSString *key;
176    NSDictionary *pageStatistics;
177
178    /* application statistics */
179
180    e = [stats keyEnumerator];
181    while ((key = [e nextObject])) {
182      id value;
183      NSString *dt;
184
185      if ([key isEqualToString:@"pageStatistics"])
186        continue;
187
188      value = [stats objectForKey:key];
189
190      [response appendContentString:@"  <"];
191      [response appendContentString:key];
192
193      if ((dt = [keyToDataType objectForKey:key])) {
194        [response appendContentString:@" dt:dt='"];
195        [response appendContentString:dt];
196        [response appendContentString:@"'"];
197      }
198
199      [response appendContentString:@">"];
200
201      [response appendContentHTMLString:[value stringValue]];
202
203      [response appendContentString:@"</"];
204      [response appendContentString:key];
205      [response appendContentString:@">\n"];
206    }
207
208    /* memory statistics */
209
210    {
211      NSDictionary *mem;
212
213      mem = [app memoryStatistics];
214
215      if ([mem count] > 0) {
216        [response appendContentString:@"  <memory>\n"];
217
218        e = [mem keyEnumerator];
219        while ((key = [e nextObject])) {
220          id       value;
221          NSString *dt;
222
223          value = [mem objectForKey:key];
224
225          [response appendContentString:@"  <"];
226          [response appendContentString:key];
227
228          if ((dt = [keyToDataType objectForKey:key])) {
229            [response appendContentString:@" dt:dt='"];
230            [response appendContentString:dt];
231            [response appendContentString:@"'"];
232          }
233
234          [response appendContentString:@">"];
235
236          [response appendContentHTMLString:[value stringValue]];
237
238          [response appendContentString:@"</"];
239          [response appendContentString:key];
240          [response appendContentString:@">\n"];
241        }
242
243        [response appendContentString:@"  </memory>\n"];
244      }
245    }
246
247    /* page statistics */
248
249    pageStatistics = [stats objectForKey:@"pageStatistics"];
250
251    [response appendContentString:@"  <pages>\n"];
252
253    e = [pageStatistics keyEnumerator];
254    while ((key = [e nextObject])) {
255      NSDictionary *stats;
256      NSEnumerator *e2;
257      NSString     *key2;
258
259      stats = [pageStatistics objectForKey:key];
260      e2    = [stats keyEnumerator];
261
262      [response appendContentString:@"    <page name='"];
263      [response appendContentString:key];
264      [response appendContentString:@"'>\n"];
265
266      while ((key2 = [e2 nextObject])) {
267        id value;
268        NSString *dt;
269
270        value = [stats objectForKey:key2];
271
272        [response appendContentString:@"      <"];
273        [response appendContentString:key2];
274
275        if ((dt = [keyToDataType objectForKey:key2])) {
276          [response appendContentString:@" dt:dt='"];
277          [response appendContentString:dt];
278          [response appendContentString:@"'"];
279        }
280
281        [response appendContentString:@">"];
282
283        [response appendContentHTMLString:[value stringValue]];
284
285        [response appendContentString:@"</"];
286        [response appendContentString:key2];
287        [response appendContentString:@">\n"];
288      }
289      [response appendContentString:@"    </page>\n"];
290    }
291
292    [response appendContentString:@"  </pages>\n"];
293  }
294
295  [response appendContentString:@"</application>\n"];
296
297  return response;
298}
299
300@end /* WODirectAction(WOStats) */
301