1 package body FND_LOG as
2 /* $Header: AFUTLOGB.pls 120.4.12000000.2 2007/09/25 14:21:31 rlandows ship $ */
3 /* Documentation for this package is at */
4 /* http://www-apps.us.oracle.com/logging/ */
5
6 /*
7 ** EXCEPTIONS
8 */
9 bad_parameter EXCEPTION;
10 PRAGMA EXCEPTION_INIT(bad_parameter, -06501); -- program error
11
12 /*
13 ** PACKAGE VARIABLES
14 */
15 /* Removing these from pkg body as they already exist in spec. 10.1.0.4 throws
16 error in case of duplicate definition
17
18 LEVEL_UNEXPECTED CONSTANT NUMBER := 6;
19 LEVEL_ERROR CONSTANT NUMBER := 5;
20 LEVEL_EXCEPTION CONSTANT NUMBER := 4;
21 LEVEL_EVENT CONSTANT NUMBER := 3;
22 LEVEL_PROCEDURE CONSTANT NUMBER := 2;
23 LEVEL_STATEMENT CONSTANT NUMBER := 1;
24 */
25 /* Message buffer */
26 internal_messages VARCHAR2(10000);
27
28 /*
29 ** PRIVATE PROCEDURES
30 */
31
32 /* Set the contents of the message buffer */
33 procedure INTERNAL_MESSAGE(msg VARCHAR2) IS
34 begin
35 internal_messages := internal_messages || msg || fnd_global.newline;
36 end;
37
38 /* Set error message and raise exception for unexpected sql errors */
39
40 procedure GENERIC_ERROR(routine in varchar2,
41 errcode in number,
42 errmsg in varchar2) is
43 begin
44 fnd_message.set_name('FND', 'SQL_PLSQL_ERROR');
45 fnd_message.set_token('ROUTINE', routine);
46 fnd_message.set_token('ERRNO', errcode);
47 fnd_message.set_token('REASON', errmsg);
48 app_exception.raise_exception;
49 end;
50
51
52
53 FUNCTION STR_UNCHKED_INT_WITH_CONTEXT(
54 LOG_LEVEL IN NUMBER,
55 MODULE IN VARCHAR2,
56 MESSAGE_TEXT IN VARCHAR2,
57 ENCODED IN VARCHAR2 DEFAULT 'N',
58 NODE IN VARCHAR2 DEFAULT NULL,
59 NODE_IP_ADDRESS IN VARCHAR2 DEFAULT NULL,
60 PROCESS_ID IN VARCHAR2 DEFAULT NULL,
61 JVM_ID IN VARCHAR2 DEFAULT NULL,
62 THREAD_ID IN VARCHAR2 DEFAULT NULL,
63 AUDSID IN NUMBER DEFAULT NULL,
64 DB_INSTANCE IN NUMBER DEFAULT NULL) RETURN NUMBER is
65
66 CALL_STACK VARCHAR2(4000) := NULL;
67 ERR_STACK VARCHAR2(4000) := NULL;
68 l_seq NUMBER;
69
70 begin
71
72 if (LOG_LEVEL >= FND_LOG.LEVEL_EXCEPTION) THEN
73 CALL_STACK := DBMS_UTILITY.FORMAT_CALL_STACK;
74 ERR_STACK := DBMS_UTILITY.FORMAT_ERROR_STACK;
75 end if;
76
77 l_seq := FND_LOG_REPOSITORY.STR_UNCHKED_INT_WITH_CONTEXT(
78 LOG_LEVEL => LOG_LEVEL,
79 MODULE => MODULE,
80 MESSAGE_TEXT => MESSAGE_TEXT,
81 ENCODED => ENCODED,
82 NODE => NODE,
83 NODE_IP_ADDRESS => NODE_IP_ADDRESS,
84 PROCESS_ID => PROCESS_ID,
85 JVM_ID => JVM_ID,
86 THREAD_ID => THREAD_ID,
87 AUDSID => AUDSID,
88 DB_INSTANCE => DB_INSTANCE,
89 CALL_STACK => CALL_STACK,
90 ERR_STACK => ERR_STACK);
91
92 return l_seq;
93
94 end;
95
96
97
98 /*
99 ** PUBLIC PROCEDURES
100 */
101
102 /*
103 ** FND_LOG.INIT_TRANSACTION
104 **
105 ** Description:
106 ** Initializes a log transaction. A log transaction
107 ** corresponds to an instance or invocation of a single
108 ** component. (e.g. A concurrent request, service process,
109 ** open form, ICX function)
110 **
111 ** This routine should be called only after
112 ** FND_GLOBAL.INITIALIZE, since some of the context information
113 ** is retrieved from FND_GLOBAL.
114 **
115 ** Arguments:
116 ** CONC_REQUEST_ID - Concurrent request id
117 ** FORM_ID - Form id
118 ** FORM_APPLICATION_ID - Form application id
119 ** CONCURRENT_PROCESS_ID - Service process id
120 ** CONCURRENT_QUEUE_ID - Service queue id
121 ** QUEUE_APPLICATION_ID - Service queue application id
122 **
123 ** Use only the arguments that apply to the caller.
124 ** Any argument that does not apply should be passed as NULL
125 ** i.e. when calling from a form, pass in FORM_ID and FORM_APPLICATION_ID
126 ** and leave all other parameters NULL.
127 **
128 ** Returns:
129 ** ID of the log transaction context
130 **
131 */
132 FUNCTION INIT_TRANSACTION (CONC_REQUEST_ID IN NUMBER DEFAULT NULL,
133 FORM_ID IN NUMBER DEFAULT NULL,
134 FORM_APPLICATION_ID IN NUMBER DEFAULT NULL,
135 CONCURRENT_PROCESS_ID IN NUMBER DEFAULT NULL,
136 CONCURRENT_QUEUE_ID IN NUMBER DEFAULT NULL,
137 QUEUE_APPLICATION_ID IN NUMBER DEFAULT NULL)
138 return NUMBER is
139
140 l_transaction_context_id number;
141 begin
142
143 l_transaction_context_id :=
144 FND_LOG_REPOSITORY.INIT_TRANS_INT_WITH_CONTEXT(
145 CONC_REQUEST_ID => CONC_REQUEST_ID,
146 FORM_ID => FORM_ID,
147 FORM_APPLICATION_ID => FORM_APPLICATION_ID,
148 CONCURRENT_PROCESS_ID => CONCURRENT_PROCESS_ID,
149 CONCURRENT_QUEUE_ID => CONCURRENT_QUEUE_ID,
150 QUEUE_APPLICATION_ID => QUEUE_APPLICATION_ID);
151 return l_transaction_context_id;
152
153 exception
154 when others then
155 generic_error('FND_LOG.INIT_TRANSACTION', SQLCODE, SQLERRM);
156 return -1;
157
158
159 end INIT_TRANSACTION;
160
161 /*
162 ** FND_LOG.SET_TRANSACTION
163 ** Description:
164 ** Sets the log transaction ID for the current DB connection.
165 ** This routine should be used whenever the database connection
166 ** changes within the context of a transaction. For example, this
167 ** routine will be used for successive hits within the same ICX
168 ** transaction or when a concurrent process reconnects to the database.
169 **
170 ** Arguments:
171 ** Log_Transaction
172 **
173 */
174 PROCEDURE SET_TRANSACTION (TRANS_CONTEXT_ID IN NUMBER) is
175 dummy number;
176
177 begin
178
179 select count(*)
180 into dummy
181 from FND_LOG_TRANSACTION_CONTEXT
182 where TRANSACTION_CONTEXT_ID = TRANS_CONTEXT_ID;
183
184 if (dummy = 1) then
185 FND_LOG.G_TRANSACTION_CONTEXT_ID := TRANS_CONTEXT_ID;
186 else
187 internal_message('bad TRANSACTION_CONTEXT_ID: '|| TRANS_CONTEXT_ID);
188 internal_message('TRANSACTION_CONTEXT_ID not found in table FND_LOG_TRANSACTION_CONTEXT');
189 raise bad_parameter;
190 end if;
191
192 end SET_TRANSACTION;
193
194 /*
195 ** Writes the message to the log file for the spec'd level and module
196 ** if logging is enabled for this level and module
197 */
198 PROCEDURE STRING(LOG_LEVEL IN NUMBER,
199 MODULE IN VARCHAR2,
200 MESSAGE IN VARCHAR2) is
201
202 l_seq number;
203 begin
204 /* Short circuit if logging not turned on at this level */
205 if (LOG_LEVEL < G_CURRENT_RUNTIME_LEVEL) then
206 return;
207 end if;
208
209 if FND_LOG_REPOSITORY.CHECK_ACCESS_INTERNAL (MODULE, LOG_LEVEL) then
210
211 l_seq := STR_UNCHKED_INT_WITH_CONTEXT(
212 LOG_LEVEL => LOG_LEVEL,
213 MODULE => MODULE,
214 MESSAGE_TEXT => MESSAGE);
215 end if;
216
217 exception
218 when others then
219 NULL; /* supress the exception */
220 end;
221
222 /*
223 ** Writes the message with context information to the log file for
224 ** the spec'd level and module if logging is enabled for this level
225 ** and module
226 */
227 PROCEDURE STRING_WITH_CONTEXT(LOG_LEVEL IN NUMBER,
228 MODULE IN VARCHAR2,
229 MESSAGE IN VARCHAR2,
230 ENCODED IN VARCHAR2 DEFAULT NULL,
231 NODE IN VARCHAR2 DEFAULT NULL,
232 NODE_IP_ADDRESS IN VARCHAR2 DEFAULT NULL,
233 PROCESS_ID IN VARCHAR2 DEFAULT NULL,
234 JVM_ID IN VARCHAR2 DEFAULT NULL,
235 THREAD_ID IN VARCHAR2 DEFAULT NULL,
236 AUDSID IN NUMBER DEFAULT NULL,
237 DB_INSTANCE IN NUMBER DEFAULT NULL) is
238
239 l_seq number;
240
241 begin
242 /* Short circuit if logging not turned on at this level */
243 if (LOG_LEVEL < G_CURRENT_RUNTIME_LEVEL) then
244 return;
245 end if;
246
247 if FND_LOG_REPOSITORY.CHECK_ACCESS_INTERNAL (MODULE, LOG_LEVEL) then
248
249 l_seq := STR_UNCHKED_INT_WITH_CONTEXT(
250 LOG_LEVEL => LOG_LEVEL,
251 MODULE => MODULE,
252 MESSAGE_TEXT => MESSAGE,
253 ENCODED => ENCODED,
254 NODE => NODE,
255 NODE_IP_ADDRESS => NODE_IP_ADDRESS,
256 PROCESS_ID => PROCESS_ID,
257 JVM_ID => JVM_ID,
258 THREAD_ID => THREAD_ID,
259 AUDSID => AUDSID,
260 DB_INSTANCE => DB_INSTANCE);
261 end if;
262 end;
263
264 /*
265 ** Internal (private) API that handles all the logic
266 */
267 FUNCTION MESSAGE_INTERNAL(LOG_LEVEL IN NUMBER,
268 MODULE IN VARCHAR2,
269 POP_MESSAGE IN BOOLEAN DEFAULT NULL,
270 AUTO_LOG IN VARCHAR2) RETURN NUMBER is
271 msg_buf varchar2(32000);
272 l_sequence number := -1;
273 begin
274 /* Short circuit if logging not turned on at this level */
275 if (LOG_LEVEL < G_CURRENT_RUNTIME_LEVEL) then
276 return l_sequence;
277 end if;
278
279 if FND_LOG_REPOSITORY.CHECK_ACCESS_INTERNAL (MODULE, LOG_LEVEL) then
280 msg_buf := FND_MESSAGE.GET_ENCODED(AUTO_LOG);
281 l_sequence := STR_UNCHKED_INT_WITH_CONTEXT(
282 LOG_LEVEL => LOG_LEVEL,
283 MODULE => MODULE,
284 MESSAGE_TEXT => msg_buf,
285 ENCODED => 'Y');
286
287 /* No change in Message Stack if this PROCEDURE is called for Auto-Log = 'Y' */
288 if( (AUTO_LOG <> 'Y') and
289 ((pop_message = FALSE) OR (pop_message is NULL)) )then
290 FND_MESSAGE.SET_ENCODED(msg_buf);
291 end if;
292 end if;
293
294 return l_sequence;
295
296 exception
297 when others then
298 /* supress the exception */
299 return l_sequence;
300 end;
301
302 /*
303 ** Writes a message to the log file if this level and module is enabled
304 ** This requires that the message was set previously with
305 ** FND_MESSAGE.SET_NAME, SET_TOKEN, etc.
306 ** The message is popped off the message dictionary stack, if POP_MESSAGE
307 ** is TRUE. Pass FALSE for POP_MESSAGE if the message will also be
308 ** displayed to the user later. If POP_MESSAGE isn't passed, the
309 ** message will not be popped off the stack, so it must be displayed
310 ** or explicitly cleared later on.
311 */
312 PROCEDURE MESSAGE(LOG_LEVEL IN NUMBER,
313 MODULE IN VARCHAR2,
314 POP_MESSAGE IN BOOLEAN DEFAULT NULL,
315 AUTO_LOG IN VARCHAR2)
316 is
317 l_sequence number;
318 begin
319 l_sequence := MESSAGE_INTERNAL(LOG_LEVEL, MODULE, POP_MESSAGE, AUTO_LOG);
320 end;
321
322 PROCEDURE MESSAGE(LOG_LEVEL IN NUMBER,
323 MODULE IN VARCHAR2,
324 POP_MESSAGE IN BOOLEAN DEFAULT NULL)
325 is
326 begin
327 /* Message is already being logged, so AUTO_LOG = 'N' */
328 MESSAGE(LOG_LEVEL, MODULE, POP_MESSAGE, 'N');
329 end;
330
331 /*
332 ** Writes a message to the log file if this level and module is enabled
333 ** The message gets set previously with FND_MESSAGE.SET_NAME,
334 ** SET_TOKEN, etc.
335 ** The message is popped off the message dictionary stack, if POP_MESSAGE
336 ** is TRUE. Pass FALSE for POP_MESSAGE if the message will also be
337 ** displayed to the user later.
338 ** Code Sample:
339 ** if( FND_LOG.LEVEL_UNEXPECTED >=
340 ** FND_LOG.G_CURRENT_RUNTIME_LEVEL) then
341 ** FND_MESSAGE.SET_NAME(...); -- Set message
342 ** FND_MESSAGE.SET_TOKEN(...); -- Set token in message
343 ** ATTACHMENT_ID := FND_LOG.MESSAGE_WITH_ATTACHMENT(FND_LOG.LEVEL_UNEXPECTED,...,TRUE);
344 ** if ( ATTACHMENT_ID <> -1 ) then
345 ** -- For ASCII data use WRITE
346 ** FND_LOG_ATTACHMENT.WRITE(ATTACHMENT_ID, ...);
347 ** -- For Non-ASCII data use WRITE_RAW
348 ** FND_LOG_ATTACHMENT.WRITE_RAW(ATTACHMENT_ID, ...);
349 ** FND_LOG_ATTACHMENT.CLOSE(ATTACHMENT_ID);
350 ** end if;
351 ** end if;
352 */
353 FUNCTION MESSAGE_WITH_ATTACHMENT(LOG_LEVEL IN NUMBER,
354 MODULE IN VARCHAR2,
355 POP_MESSAGE IN BOOLEAN DEFAULT NULL,
356 P_CHARSET IN VARCHAR2 DEFAULT 'ascii',
357 P_MIMETYPE IN VARCHAR2 DEFAULT 'text/html',
358 P_ENCODING IN VARCHAR2 DEFAULT NULL,
359 P_LANG IN VARCHAR2 DEFAULT NULL,
360 P_FILE_EXTN IN VARCHAR2 DEFAULT 'txt',
361 P_DESC IN VARCHAR2 DEFAULT NULL) RETURN NUMBER is
362 l_sequence number := -1;
363 begin
364 l_sequence := MESSAGE_INTERNAL(LOG_LEVEL, MODULE, POP_MESSAGE, 'N');
365 if ( l_sequence > 0 ) then
366 FND_LOG_REPOSITORY.INSERT_BLOB(l_sequence, P_CHARSET, P_MIMETYPE,
367 P_ENCODING, P_LANG, P_FILE_EXTN, P_DESC);
368 end if;
369 return l_sequence;
370 end;
371
372 /*
373 ** Writes a message with context to the log file if this level and
374 ** module is enabled. This requires that the message was set
375 ** previously with FND_MESSAGE.SET_NAME, SET_TOKEN, etc.
376 ** The message is popped off the message dictionary stack, if POP_MESSAGE
377 ** is TRUE. Pass FALSE for POP_MESSAGE if the message will also be
378 ** displayed to the user later. If POP_MESSAGE isn't passed, the
379 ** message will not be popped off the stack, so it must be displayed
380 ** or explicitly cleared later on.
381 */
382 PROCEDURE MESSAGE_WITH_CONTEXT(LOG_LEVEL IN NUMBER,
383 MODULE IN VARCHAR2,
384 POP_MESSAGE IN BOOLEAN DEFAULT NULL, --Default FALSE
385 NODE IN VARCHAR2 DEFAULT NULL,
386 NODE_IP_ADDRESS IN VARCHAR2 DEFAULT NULL,
387 PROCESS_ID IN VARCHAR2 DEFAULT NULL,
388 JVM_ID IN VARCHAR2 DEFAULT NULL,
389 THREAD_ID IN VARCHAR2 DEFAULT NULL,
390 AUDSID IN NUMBER DEFAULT NULL,
391 DB_INSTANCE IN NUMBER DEFAULT NULL) is
392 msg_buf varchar2(32000);
393 l_seq number;
394 begin
395 /* Short circuit if logging not turned on at this level */
396 if (LOG_LEVEL < G_CURRENT_RUNTIME_LEVEL) then
397 return;
398 end if;
399
400 if FND_LOG_REPOSITORY.CHECK_ACCESS_INTERNAL (MODULE, LOG_LEVEL) then
401 msg_buf := FND_MESSAGE.GET_ENCODED;
402
403 l_seq := STR_UNCHKED_INT_WITH_CONTEXT(
404 LOG_LEVEL => LOG_LEVEL,
405 MODULE => MODULE,
406 MESSAGE_TEXT => msg_buf,
407 ENCODED => 'Y',
408 NODE => NODE,
409 NODE_IP_ADDRESS => NODE_IP_ADDRESS,
410 PROCESS_ID => PROCESS_ID,
411 JVM_ID => JVM_ID,
412 THREAD_ID => THREAD_ID,
413 AUDSID => AUDSID,
414 DB_INSTANCE => DB_INSTANCE);
415 if((pop_message = FALSE) OR (pop_message is NULL))then
416 FND_MESSAGE.SET_ENCODED(msg_buf);
417 end if;
418
419 end if;
420 end;
421
422
423 /*
424 ** FND_LOG.WORK_METRIC
425 ** Description:
426 ** Writes a metric value out to the FND tables in an
427 ** autonomous transaction. Posting to the Business Event
428 ** system is deferred until WORK_METRICS_EVENT is called.
429 **
430 ** Arguments:
431 ** Module - Module name (See FND_LOG standards.)
432 ** Metric_code - Internal name of metric.
433 ** Metric_value - Value for metric (string, number, or date)
434 **
435 */
436
437 procedure WORK_METRIC (MODULE IN VARCHAR2,
438 METRIC_CODE IN VARCHAR2,
439 METRIC_VALUE IN VARCHAR2) is
440
441 begin
442 FND_LOG_REPOSITORY.METRIC_INTERNAL_WITH_CONTEXT(
443 MODULE => MODULE,
444 METRIC_CODE => METRIC_CODE,
445 METRIC_VALUE_STRING => METRIC_VALUE);
446 end WORK_METRIC;
447
448 procedure WORK_METRIC (MODULE IN VARCHAR2,
449 METRIC_CODE IN VARCHAR2,
450 METRIC_VALUE IN NUMBER) is
451
452 begin
453 FND_LOG_REPOSITORY.METRIC_INTERNAL_WITH_CONTEXT(
454 MODULE => MODULE,
455 METRIC_CODE => METRIC_CODE,
456 METRIC_VALUE_NUMBER => METRIC_VALUE);
457 end WORK_METRIC;
458
459 procedure WORK_METRIC (MODULE IN VARCHAR2,
460 METRIC_CODE IN VARCHAR2,
461 METRIC_VALUE IN DATE) is
462
463 begin
464 FND_LOG_REPOSITORY.METRIC_INTERNAL_WITH_CONTEXT(
465 MODULE => MODULE,
466 METRIC_CODE => METRIC_CODE,
467 METRIC_VALUE_DATE => METRIC_VALUE);
468 end WORK_METRIC;
469
470 /*
471 ** FND_LOG.WORK_METRICS_EVENT
472 ** Description:
473 ** Posts the pending metrics for the current component
474 ** session to the Business Event system and updates the pending
475 ** metrics with the event key. The metrics will be bundled in an
476 ** XML message included in the event. The event will be named:
477 ** "oracle.apps.fnd.system.metrics"
478 **
479 ** Arguments:
480 ** CONTEXT_ID ID of the context to post the metrics event for.
481 ** Use NULL for the current context.
482 */
483
484 PROCEDURE WORK_METRICS_EVENT(CONTEXT_ID IN NUMBER DEFAULT NULL) IS
485 begin
486
487 FND_LOG_REPOSITORY.METRICS_EVENT_INT_WITH_CONTEXT(CONTEXT_ID);
488
489 end WORK_METRICS_EVENT;
490
491 /*
492 ** FND_LOG.GET_TEXT
493 **
494 ** Description:
495 ** Retrieves the fully translated message text, given a log sequence ID
496 **
497 ** Arguments:
498 ** log_sequence_id - FND_LOG message identifier.
499 ** lang - Language code for translation (optional).
500 **
501 ** Returns:
502 ** If an encoded message, the full translated text of the message.
503 ** If message not encoded, the text of the message as logged.
504 ** Returns NULL if the message cannot be found.
505 */
506 FUNCTION GET_TEXT(LOG_SEQUENCE_ID IN NUMBER,
507 LANG IN VARCHAR2 DEFAULT NULL
508 ) RETURN VARCHAR2 is
509 --6434437, the tok_val variable was too small
510 --I also went ahead and modified msg_text and msg just in case
511 --the underlying columns are changed in the future.
512
513 msg_text fnd_log_messages.message_text%type;
514 msg fnd_new_messages.message_text%type;
515 tok_val fnd_log_messages.message_text%type;
516
517
518 encoded varchar2(1);
519 msg_app_short_name varchar2(50);
520 msg_name varchar2(30);
521 tok_nam varchar2(30);
522 tok_type varchar2(1);
523 srch varchar2(2000);
524 pos number;
525 nextpos number;
526 data_size number;
527
528 begin
529
530
531 begin
532 select MESSAGE_TEXT, DECODE(ENCODED, 'Y', 'Y', 'N')
533 into msg_text, encoded
534 from FND_LOG_MESSAGES
535 where LOG_SEQUENCE = LOG_SEQUENCE_ID;
536
537 if (encoded = 'N') then
538 return msg_text;
539 end if;
540
541 exception
542 when no_data_found then
543 msg_text := '';
544 return msg_text;
545 end;
546
547
548 if (LANG is not NULL) then
549 begin
550 FND_GLOBAL.SET_NLS_CONTEXT(p_nls_language => LANG);
551 exception
552 when others then
553 /*--------------------------------------------------------------+
554 | If LANG parameter is bad, set a message then continue in the |
555 | language of the current database session. |
556 +--------------------------------------------------------------*/
557 FND_MESSAGE.SET_NAME ('FND', 'SQL-Generic error');
558 FND_MESSAGE.SET_TOKEN ('ERRNO', sqlcode, FALSE);
559 FND_MESSAGE.SET_TOKEN ('REASON', sqlerrm, FALSE);
560 FND_MESSAGE.SET_TOKEN ('ROUTINE', 'FND_LOG.GET_TEXT', FALSE);
561 end;
562 end if;
563
564 begin
565 FND_MESSAGE.PARSE_ENCODED(msg_text,
566 msg_app_short_name,
567 msg_name);
568 /* GET_STRING with Auto-Log = 'N' */
569 msg := FND_MESSAGE.GET_STRING(msg_app_short_name,
570 msg_name, 'N');
571 exception
572 when others then
573 /*--------------------------------------------------------------+
574 | If it this is not really an encoded message, then |
575 | FND_MESSAGE.PARSE_ENCODED may have tried to put entire |
576 | msg_text in msg_app_short_name. |
577 +--------------------------------------------------------------*/
578 return msg_text;
579 end;
580
581 /*--------------------------------------------------------------+
582 | It seems to be an authentic encoded message. |
583 +---------------------------------------------------------------*/
584
585 /* Get rid of msg_app_short_name, msg_name */
586 pos := INSTRB(msg_text, chr(0), 1, 2) + 1;
587 msg_text := SUBSTRB(msg_text, pos);
588
589 /* Start the same routine from FND_MESSAGE.GET */
590 pos := 1;
591 data_size := LENGTH(msg_text);
592 while pos < data_size loop
593 tok_type := SUBSTR(msg_text, pos, 1);
594 pos := pos + 2;
595 nextpos := INSTR(msg_text, chr(0), pos);
596 if (nextpos = 0) then /* For bug 1893617 */
597 exit; /* Should never happen, but prevent spins on bad data*/
598 end if;
599 tok_nam := SUBSTR(msg_text, pos, nextpos - pos);
600 pos := nextpos + 1;
601 nextpos := INSTR(msg_text, chr(0), pos);
602 if (nextpos = 0) then /* For bug 1893617 */
603 exit; /* Should never happen, but prevent spins on bad data*/
604 end if;
605 tok_val := SUBSTR(msg_text, pos, nextpos - pos);
606 pos := nextpos + 1;
607
608 if (tok_type = 'Y') then /* translated token */
609 /* GET_STRING with Auto-Log = 'N' */
610 tok_val := FND_MESSAGE.GET_STRING(msg_app_short_name, tok_val, 'N');
611 elsif (tok_type = 'S') then /* SQL query token */
612 tok_val := FND_MESSAGE.FETCH_SQL_TOKEN(tok_val);
613 end if;
614 srch := '&' || tok_nam;
615 if (INSTR(msg, srch) <> 0) then
616 msg := SUBSTRB(REPLACE(msg, srch, tok_val),1,2000);
617 else
618 /* try the uppercased version of the token name in case */
619 /* the caller is (wrongly) passing a mixed case token name */
620 /* Because begin July 99 all tokens in msg text should be */
621 /* uppercase. */
622 srch := '&' || UPPER(tok_nam);
623 if (INSTR(msg, srch) <> 0) then
624 msg := SUBSTRB(REPLACE(msg, srch, tok_val),1,2000);
625 else
626 msg :=SUBSTRB(msg||' ('||tok_nam||'='||tok_val||')',1,2000);
627 end if;
628 end if;
629 end loop;
630 /* double ampersands don't have anything to do with tokens, they */
631 /* represent access keys. So we translate them to single ampersands*/
632 /* so that the access key code will recognize them. */
633 msg := SUBSTRB(REPLACE(msg, '&&', '&'),1,2000);
634 return msg;
635 end GET_TEXT;
636
637 /*
638 ** Tests whether logging is enabled for this level and module, to
639 ** avoid the performance penalty of building long debug message
640 ** strings unnecessarily.
641 */
642 FUNCTION TEST(LOG_LEVEL IN NUMBER,
643 MODULE IN VARCHAR2) RETURN BOOLEAN is
644 begin
645 if ( LOG_LEVEL < G_CURRENT_RUNTIME_LEVEL ) then
646 return FALSE;
647 end if;
648 return FND_LOG_REPOSITORY.CHECK_ACCESS_INTERNAL (MODULE, LOG_LEVEL);
649 end;
650
651
652 /**
653 * Procedure to enable PL/SQL Buffered Logging (for Batch Mode).
654 * Caller is responsible for calling RESET_BUFFERED_MODE to flush
655 * messages at end. Only messages with log_level < 4 are bufferable.
656 * All error messages (log_level >= 4) are logged immediately.
657 *
658 * Internally reads AFLOG_BUFFER_MODE Profile and if !=0
659 * buffers messages in PL/SQL Collection for Bulk-Inserting.
660 */
661 PROCEDURE SET_BUFFERED_MODE is
662 begin
663 FND_LOG_REPOSITORY.SET_BUFFERED_MODE;
664 end SET_BUFFERED_MODE;
665
666 /**
667 * Flushes any buffered messages, and switches back to the
668 * default synchronous (non-buffered) logging.
669 */
670 PROCEDURE RESET_BUFFERED_MODE is
671 begin
672 FND_LOG_REPOSITORY.RESET_BUFFERED_MODE;
673 end RESET_BUFFERED_MODE;
674
675 /**
676 * API for raising a proxy alert on behalf of the given
677 * concurrent request. The transaction context for the alert is set to
678 * that of the given request ID. The current transaction context is also
679 * captured as a parent context.
680 *
681 * This API does the following:
682 * 1) Sets a child context for the given request ID
683 * 2) Raises the proxy alert by calling fnd_log.message in the normal
684 * fashion
685 * 3) Clears the child context.
686 */
687 PROCEDURE PROXY_ALERT_FOR_CONC_REQ(
688 MODULE IN VARCHAR2,
689 POP_MESSAGE IN BOOLEAN DEFAULT NULL,
690 REQUEST_ID IN NUMBER) is
691 BEGIN
692 if (fnd_log.level_unexpected >= fnd_log.g_current_runtime_level) then
693 fnd_log_repository.set_child_context_for_conc_req(REQUEST_ID);
694 fnd_log.message(
695 log_level => fnd_log.level_unexpected,
696 module => MODULE,
697 pop_message => POP_MESSAGE);
698 fnd_log_repository.clear_child_context;
699 end if;
700 END PROXY_ALERT_FOR_CONC_REQ;
701
702 end FND_LOG;