1 PACKAGE BODY FND_OAM_DEBUG as
2 /* $Header: AFOAMDBGB.pls 120.5 2005/10/14 15:00 ilawler noship $ */
3
4 ----------------------------------------
5 -- Private Body Constants
6 ----------------------------------------
7 PKG_NAME CONSTANT VARCHAR2(20) := 'DEBUG.';
8 B_DEFAULT_FILE_PREFIX CONSTANT VARCHAR2(20) := 'fnd_oam_debug';
9
10 -- State variables
11 b_log_level NUMBER := NULL; --defaulting to NULL allows fnd_log's level to be used by default
12 b_include_timestamp BOOLEAN := FALSE;
13 b_use_indentation BOOLEAN := FALSE;
14 b_indent_level NUMBER := 0;
15 b_fd UTL_FILE.FILE_TYPE;
16
17 --store what styles are enabled
18 b_style_screen BOOLEAN := FALSE;
19 b_style_file BOOLEAN := FALSE;
20 b_style_fnd_log BOOLEAN := TRUE; --by default, only enable fnd_log
21
22 -- Private helper to close the log file, also turns off the "file" style
23 FUNCTION CLOSE_LOG_FILE
24 RETURN BOOLEAN
25 IS
26 BEGIN
27 IF UTL_FILE.IS_OPEN(b_fd) THEN
28 UTL_FILE.FCLOSE(b_fd);
29 END IF;
30 b_style_file := FALSE;
31 b_fd := NULL;
32 RETURN TRUE;
33 EXCEPTION
34 WHEN OTHERS THEN
35 RETURN FALSE;
36 END;
37
38 -- Public
39 FUNCTION INIT_LOG(p_include_timestamp IN BOOLEAN,
40 p_use_indentation IN BOOLEAN,
41 p_start_indent_level IN NUMBER)
42 RETURN BOOLEAN
43 IS
44 l_ignore BOOLEAN;
45 BEGIN
46 --set the state from the provided values
47 b_include_timestamp := NVL(p_include_timestamp, FALSE);
48 b_use_indentation := NVL(p_use_indentation, FALSE);
49 b_indent_level := NVL(p_start_indent_level, 0);
50
51 --default the rest of the state to its start position
52 b_style_screen := FALSE;
53 IF b_style_file THEN
54 l_ignore := CLOSE_LOG_FILE;
55 END IF;
56 b_style_fnd_log := TRUE;
57
58 --also reset the internal log level
59 b_log_level := NULL;
60
61 RETURN TRUE;
62 END;
63
64 -- Public
65 FUNCTION FLUSH_LOG
66 RETURN BOOLEAN
67 IS
68 BEGIN
69 -- we can only flush a file
70 IF b_style_file THEN
71 UTL_FILE.FFLUSH(b_fd);
72 END IF;
73 RETURN TRUE;
74 EXCEPTION
75 WHEN OTHERS THEN
76 RETURN FALSE;
77 END;
78
79 -- Public
80 FUNCTION CLOSE_LOG
81 RETURN BOOLEAN
82 IS
83 BEGIN
84 --reset to defaults
85 b_style_screen := FALSE;
86 IF b_style_file THEN
87 IF NOT CLOSE_LOG_FILE THEN
88 RETURN FALSE;
89 END IF;
90 END IF;
91 b_style_fnd_log := TRUE;
92
93 b_include_timestamp := FALSE;
94 b_use_indentation := FALSE;
95 b_indent_level := 0;
96
97 b_log_level := NULL;
98 RETURN TRUE;
99 EXCEPTION
100 WHEN OTHERS THEN
101 RETURN FALSE;
102 END;
103
104 -- Public
105 FUNCTION ENABLE_STYLE_SCREEN
106 RETURN BOOLEAN
107 IS
108 BEGIN
109 b_style_screen := TRUE;
110 RETURN TRUE;
111 END;
112
113 -- Private helper to actually dump a string to a log file.
114 PROCEDURE LOG_FILE_WRITE(s IN VARCHAR2,
115 p_flush IN BOOLEAN)
116 IS
117 BEGIN
118 UTL_FILE.PUT_LINE(b_fd, s);
119 IF (p_flush) THEN
120 UTL_FILE.FFLUSH(b_fd);
121 END IF;
122 EXCEPTION
123 WHEN OTHERS THEN
124 null;
125 END;
126
127 -- Public
128 FUNCTION ENABLE_STYLE_FILE(p_file_name_prefix IN VARCHAR2 DEFAULT NULL,
129 p_include_unique_suffix IN BOOLEAN DEFAULT NULL,
130 p_write_header IN BOOLEAN DEFAULT NULL)
131 RETURN BOOLEAN
132 IS
133 l_ignore BOOLEAN;
134 l_prefix VARCHAR2(512) := p_file_name_prefix;
135 l_suffix VARCHAR2(512) := '';
136 l_tmp_dir VARCHAR2(512);
137 l_name VARCHAR2(2048);
138 BEGIN
139 --if style file is already enabled, close the current file
140 IF b_style_file THEN
141 l_ignore := CLOSE_LOG_FILE;
142 END IF;
143
144 --get the directory where we can write
145 SELECT value
146 INTO l_tmp_dir
147 FROM V$PARAMETER
148 WHERE name = 'utl_file_dir';
149
150 IF l_tmp_dir IS NULL THEN
151 RETURN FALSE;
152 END IF;
153
154 --get the first directory
155 IF instr(l_tmp_dir,',') > 0 THEN
156 l_tmp_dir := substr(l_tmp_dir,
157 1,
158 instr(l_tmp_dir,',')-1);
159 END IF;
160
161 --create the file name using the prefix and suffix
162 IF p_file_name_prefix IS NULL THEN
163 l_prefix := B_DEFAULT_FILE_PREFIX;
164 END IF;
165 IF p_include_unique_suffix IS NOT NULL AND p_include_unique_suffix THEN
166 SELECT substr(round(to_char(systimestamp, 'FF'),-5),1,4)
167 INTO l_suffix
168 FROM DUAL;
169 END IF;
170 l_name := l_prefix||l_suffix||'.txt';
171
172 --issue the file open API
173 b_fd := UTL_FILE.FOPEN(l_tmp_dir,
174 l_name,
175 'w');
176
177 --Yields GSCC warning, ignore
178 dbms_output.put_line('FND_OAM_DEBUG: Opened File Log: ('||l_tmp_dir||'/'||l_name||')');
179
180 b_style_file := TRUE;
181
182 --if we're writing a header, go ahead and do that.
183 IF p_write_header THEN
184 LOG_FILE_WRITE('## Opened ('||to_char(SYSDATE, 'YYYY/MM/DD HH24:MI:SS')||')',
185 TRUE);
186 END IF;
187 RETURN TRUE;
188 EXCEPTION
189 WHEN OTHERS THEN
190 RETURN FALSE;
191 END;
192
193 -- Public
194 FUNCTION ENABLE_STYLE_FND_LOG
195 RETURN BOOLEAN
196 IS
197 BEGIN
198 b_style_fnd_log := TRUE;
199 RETURN TRUE;
200 END;
201
202 -- Public
203 FUNCTION DISABLE_STYLE(p_style IN VARCHAR2)
204 RETURN BOOLEAN
205 IS
206 l_bool BOOLEAN := TRUE;
207 BEGIN
208 CASE p_style
209 WHEN STYLE_SCREEN THEN
210 b_style_screen := FALSE;
211 WHEN STYLE_FILE THEN
212 l_bool := CLOSE_LOG_FILE;
213 WHEN STYLE_FND_LOG THEN
214 b_style_fnd_log := FALSE;
215 ELSE
216 RETURN FALSE;
217 END CASE;
218 RETURN l_bool;
219 END;
220
221 -- Public
222 FUNCTION TEST(p_level IN NUMBER,
223 p_module IN VARCHAR2)
224 RETURN BOOLEAN
225 IS
226 BEGIN
227 --if our internal log level is null, look elsewhere for a level
228 IF b_log_level IS NULL THEN
229 --try to defer to fnd_log
230 IF b_style_fnd_log THEN
231 RETURN (p_level >= FND_LOG.G_CURRENT_RUNTIME_LEVEL);
232 END IF;
233 ELSE
234 RETURN p_level >= b_log_level;
235 END IF;
236 RETURN TRUE;
237 END;
238
239 -- Public
240 PROCEDURE SET_LOG_LEVEL(p_level IN NUMBER)
241 IS
242 BEGIN
243 b_log_level := p_level;
244 END;
245
246 -- Public
247 PROCEDURE SET_INDENT_LEVEL(p_level IN NUMBER)
248 IS
249 BEGIN
250 b_indent_level := p_level;
251 END;
252
253 -- Private, indents the log only when indentation is enabled
254 PROCEDURE LOG_INDENT
255 IS
256 BEGIN
257 IF b_use_indentation THEN
258 b_indent_level := b_indent_level + 1;
259 END IF;
260 END;
261
262 -- Private, outdents the log only when indentation is enabled
263 PROCEDURE LOG_OUTDENT
264 IS
265 BEGIN
266 IF b_use_indentation AND b_indent_level > 0 THEN
267 b_indent_level := b_indent_level - 1;
268 END IF;
269 END;
270
271 -- Private, helper to compute the leading underscore string representing
272 -- indentation for a line. Uses underscore instead of space because dbms_output
273 -- trims leading spaces.
274 FUNCTION MAKE_INDENT_STR
275 RETURN VARCHAR2
276 IS
277 l_str VARCHAR2(2048) := '';
278 BEGIN
279 RETURN SUBSTR(RPAD(' ', b_indent_level+1, '_'), 2);
280 END;
281
282 -- Computes the change in the indent level based on certain well known strings triggering
283 -- indent and outdent.
284 FUNCTION COMPUTE_INDENT_CHANGE(s IN VARCHAR2)
285 RETURN NUMBER
286 IS
287 l_retval NUMBER := NULL;
288 l_s VARCHAR2(2048) := upper(s);
289 BEGIN
290 IF l_s = 'ENTER' THEN
291 l_retval := 1;
292 ELSIF l_s = 'EXIT' THEN
293 l_retval := -1;
294 END IF;
295
296 RETURN l_retval;
297 END;
298
299 -- Private, internal API that triggers the actual different logs to log the string in their
300 -- proper formats.
301 -- Invariant: assumes TEST has already been called
302 PROCEDURE INTERNAL_LOG(p_level IN NUMBER,
303 p_ctxt IN VARCHAR2,
304 s IN VARCHAR2)
305 IS
306 l_indent_change NUMBER;
307 l_s VARCHAR2(32767);
308 l_now TIMESTAMP;
309 BEGIN
310 IF b_use_indentation THEN
311 l_indent_change := COMPUTE_INDENT_CHANGE(s);
312 IF l_indent_change IS NOT NULL AND l_indent_change > 0 THEN
313 b_indent_level := b_indent_level + l_indent_change;
314 END IF;
315 END IF;
316
317 --prep it
318 --note: if you round the systimestamp time fraction, you lose leading zeroes, easier to just trim
319 IF NOT b_include_timestamp AND NOT b_use_indentation THEN
320 l_s := s;
321 ELSIF b_include_timestamp AND b_use_indentation THEN
322 SELECT systimestamp
323 INTO l_now
324 FROM DUAL;
325 l_s := MAKE_INDENT_STR||'('||to_char(l_now, 'HH24:MI:SS')||'.'||substr(to_char(l_now, 'FF'),1,4)||')['||p_ctxt||']('||p_level||'): "'||s||'"';
326 ELSIF b_include_timestamp THEN
327 SELECT systimestamp
328 INTO l_now
329 FROM DUAL;
330 l_s := '('||to_char(l_now, 'HH24:MI:SS')||'.'||substr(to_char(l_now, 'FF'),1,4)||')['||p_ctxt||']('||p_level||'): "'||s||'"';
331 ELSIF b_use_indentation THEN
332 l_s := MAKE_INDENT_STR||'['||p_ctxt||']('||p_level||'): "'||s||'"';
333 END IF;
334
335 --log it
336 IF b_style_fnd_log THEN
337 --For GSCC compliance, check against constant instead of calling PL/SQL function
338 --Needs to be present even though we have a TEST function
339 IF (p_level >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
340 FND_LOG.STRING(p_level,
341 p_ctxt,
342 s);
343 END IF;
344 END IF;
345 IF b_style_file THEN
346 LOG_FILE_WRITE(l_s,
347 TRUE);
348 END IF;
349 IF b_style_screen THEN
350 --Yields GSCC warning, ignore
351 dbms_output.put_line(l_s);
352 END IF;
353
354 IF b_use_indentation AND l_indent_change IS NOT NULL AND l_indent_change < 0 THEN
355 b_indent_level := b_indent_level + l_indent_change;
356 END If;
357 EXCEPTION
358 WHEN OTHERS THEN
359 --dbms_output.put_line('internal_log failed');
360 NULL;
361 END;
362
363 -- Public
364 PROCEDURE LOG(p_string IN VARCHAR2)
365 IS
366 BEGIN
367 IF TEST(1,
368 NULL) THEN
369 INTERNAL_LOG(1,
370 NULL,
371 p_string);
372 END IF;
373 END;
374
375 -- Public
376 PROCEDURE LOG(p_level IN NUMBER,
377 p_context IN VARCHAR2,
378 p_string IN VARCHAR2)
379 IS
380 BEGIN
381 IF TEST(p_level,
382 p_context) THEN
383 INTERNAL_LOG(p_level,
384 p_context,
385 p_string);
386 END IF;
387 END;
388
389 -- Public
390 PROCEDURE LOGSTAMP(p_string IN VARCHAR2)
394 IF TEST(1,
391 IS
392 l_prev_include_timestamp BOOLEAN := b_include_timestamp;
393 BEGIN
395 NULL) THEN
396 b_include_timestamp := TRUE;
397 INTERNAL_LOG(1,
398 NULL,
399 p_string);
400 b_include_timestamp := l_prev_include_timestamp;
401 END IF;
402 END;
403
404 END FND_OAM_DEBUG;