giovedì 26 marzo 2026

[ROULETTE EUROPEA] - Parte 1

 Una cosa che mi ha sempre appassionato, dai tempi dell'universita', era la possibilta' di giocare alla roulette e vincere... il sogno di molti.

Devo dire che con alcuni amici avevamo trovato dei metodi, tipo il D'alambert che pero' avevamo ottimizzato e con questo metodo anche se poco avevamo sempre vinto... nei vari casino' (Campione D'Italia, Sharm, Barcellona e per finire anche su Costa Crociera). 

Oggi pero' voglio illustrarvi tre metodi o meglio uno con due varianti A e B ed analizzare con voi le possibilita' di vincita.

Di seguito la strategia di base, massimo costo 9 fiches diciamo un 1 euro a fiche.

  • STRATEGIA INIZIALE - grizz


Di conseguenza per questa strategia avremo quanto segue:






Adesso vediamo le varianti che si possono giocare:



  • VARIANTE A



  • VARIANTE B






Nel prossimo articolo faremo una simulazione dei 3 metodi e cosa succede variando lo stake su tutte e tre le strategie.














giovedì 19 febbraio 2026

ODI - Procedura per gestione Errori

 Di seguito una semplice procedura da inserire in ODI per gestire l'uscita da un package con errore.

DECLARE

v_sess_no NUMBER := <%=odiRef.getSession( "SESS_NO" )%>;v_error_msg VARCHAR2(4000);v_error_code NUMBER;BEGIN

v_error_msg:='Errore nel package CLOUDERA_TO_APEX_PI: ODI_SESSION_ID='||v_sess_no;RAISE_APPLICATION_ERROR(-20001, v_error_msg);

EXCEPTION WHEN NO_DATA_FOUND THEN    v_error_msg:='Errore nel package CLOUDERA_TO_APEX_PI: ODI_SESSION_ID='||v_sess_no;    RAISE_APPLICATION_ERROR(-20001, v_error_msg);WHEN OTHERS THEN    v_error_msg:='Errore nel package CLOUDERA_TO_APEX_PI: ODI_SESSION_ID='||v_sess_no;    RAISE_APPLICATION_ERROR(-20001, v_error_msg);END;

La proceduta deve essere inserita o in un package o LoadPlan per l'uscita dal processo in caso di un errore. Per farla funzionare basta collegare i KO in uscita da Mapping o altro alla procedura OD che contiene quanto indicato sopra.
  1. L'istruzione <%=odiRef.getSession( "SESS_NO" )%> restituisce ID di esecuzione del mapping o altro oggetto collegato in KO alla procedura.
Nel caso in cui si voglia parametrizzarla basta verificare le api di ODI o meglio le odiRef per ottenere eventualmente altre informazioni. 


Di seguito alcune versioni scritte in linguaggi differenti dal pl-sql

1. Se sei in un ODI Procedure con Tecnologia "Jython"

import java.sql.SQLException
import oracle.odi.core.persistence.transaction.support.DefaultTransactionDefinition

sess_no = odiRef.getSession("SESS_NO")
error_msg = "Errore nel package CLOUDERA_TO_APEX_PI: ODI_SESSION_ID=" + str(sess_no)

try:
    # Qui metti la logica che può fallire
    # Esempio: raise Exception("Test errore")
    pass
    
except Exception, e:
    # Logga l'errore
    odiRef.log("ERROR", error_msg + " | Dettaglio: " + str(e))
    # Rilancia l'errore a ODI per far fallire lo step
    raise Exception(error_msg)

2. Se sei in un ODI Procedure con Tecnologia "Java BeanShell"

import oracle.odi.runtime.agent.RuntimeAgent;
import oracle.odi.core.persistence.transaction.support.DefaultTransactionDefinition;

String sessNo = "<%=odiRef.getSession("SESS_NO")%>";
String errorMsg = "Errore nel package CLOUDERA_TO_APEX_PI: ODI_SESSION_ID=" + sessNo;

try {
    // Qui metti la logica che può fallire
    // Esempio: throw new Exception("Test errore");
    
} catch (Exception e) {
    // Log su ODI
    odiRef.log("ERROR", errorMsg + " | Dettaglio: " + e.getMessage());
    // Rilancia per far fallire il task ODI
    throw new RuntimeException(errorMsg, e);
}

3. Se vuoi replicare esattamente la RAISE_APPLICATION_ERROR PL/SQL da Java via JDBC.Usalo in un Java step che apre connessione al DB Oracle:

import java.sql.*;
import oracle.jdbc.OracleConnection;

String sessNo = "<%=odiRef.getSession("SESS_NO")%>";
String errorMsg = "Errore nel package CLOUDERA_TO_APEX_PI: ODI_SESSION_ID=" + sessNo;

Connection conn = null;
CallableStatement cs = null;

try {
    // Prendi la connessione da ODI
    conn = odiRef.getJDBCConnection("SRC"); // o "WORKREP" / "TGT" in base al logical schema
    
    // Chiama direttamente RAISE_APPLICATION_ERROR
    String sql = "BEGIN RAISE_APPLICATION_ERROR(-20001, ?); END;";
    cs = conn.prepareCall(sql);
    cs.setString(1, errorMsg);
    cs.execute();
    
} catch (SQLException e) {
    odiRef.log("ERROR", "SQLCODE: " + e.getErrorCode() + " - " + errorMsg);
    throw new RuntimeException(errorMsg, e);
} finally {
    if (cs != null) cs.close();
    if (conn != null) conn.close();
}

----
Note chiave:
Per ODI:odiRef.getSession("SESS_NO") funziona solo dentro step ODI. 
Fuori devi passarlo come parametro.
Per far fallire lo step: devi fare throw new Exception() o throw new RuntimeException(). 
ODI intercetta l'eccezione e marca lo step in errore.
  • odiRef.log("ERROR", msg) 
    • scrive nel log ODI, così vedi il tuo messaggio custom nell’Operator.Codice -20001: 
    • Se lanci RuntimeException, ODI lo marca come errore generico. 
    • Se vuoi il codice -20001 nel log devi usare la versione 3 con RAISE_APPLICATION_ERROR via JDBC.

martedì 20 gennaio 2026

martedì 18 novembre 2025

RDBMS ORACLE 23ai - Utilizzo di DBMS_SCHEDULER per esecuzione script sql su filesystem

 Partiamo dal seguente riepilogo e poi approfondiamo l'ultima riga:


Se vogliamo eseguire il file   
                            /opt/sched_cdd/wrapper_0.0/sql/TESTCRT_JOB.sql 
dal filesystem NON possiamo usare PLSQL_BLOCK o SQL_SCRIPT - occorre utilizzare il tipo EXECUTABLE.

  • PASSO 1: Preparazione del file TESTCRT_2_parametri.sql sul filesystem
[oracle@localhost ~]$ more /opt/sched_cdd/wrapper_0.0/sql/TESTCRT_2_parametri.sql

DECLARE 

BEGIN

EXECUTE IMMEDIATE 'create table appo_wrapper_&p1  as select * from cat ';

EXECUTE IMMEDIATE 'create table appo_wrapper_&p2 as select * from cat ';

END;

/

  • PASSO 2: Grant necessarie per creazione/esecuzione job (eseguire come SYSDBA se necessario)

Prima di creare il job per l'esecuzione del file dobbiamo settare l'ambiente (DB) affinchè esegua il job senza problemi.

  •  Come SYSDBA, verificare le grant che mancano

SELECT 'GRANT ' || privilege || ' TO metadata_gest;' AS comando_grant
FROM (
  SELECT 'CREATE JOB' AS privilege FROM dual
  UNION ALL
  SELECT 'CREATE EXTERNAL JOB' FROM dual
  UNION ALL
  SELECT 'CREATE CREDENTIAL' FROM dual
) required
WHERE privilege NOT IN (
  SELECT privilege 
  FROM dba_sys_privs 
  WHERE grantee = 'METADATA_GEST'
);

    eseguire come SYSDBA se necessario

GRANT CREATE EXTERNAL JOB TO METADATA_GEST;

GRANT EXECUTE, DEBUG on "SYS"."DBMS_SCHEDULER" to "METADATA_GEST" ;

GRANT EXECUTE, DEBUG on "SYS"."DBMS_ISCHED" to "METADATA_GEST" ;

GRANT CREATE JOB TO metadata_gest;

GRANT CREATE CREDENTIAL TO metadata_gest;

  • PASSO 3: Creare una CREDENTIAL per l'esecuzione del job appartenent all'utente metadata_gest
    • -- username --> Utente OS con cui eseguire il comando
    • -- password --> Password Utente SO
BEGIN
  DBMS_SCHEDULER.DROP_CREDENTIAL('OS_CREDENTIAL');
END;

BEGIN
  DBMS_SCHEDULER.CREATE_CREDENTIAL(
    credential_name => 'OS_CREDENTIAL',
    username        => 'oracle',  
    password        => 'oracle'   
  );
END;

=========================
-- TEST CREDENTIAL -
=========================
  • PASSO 1: Verifica che la credential esista
SELECT  *
FROM user_scheduler_credentials
WHERE credential_name = 'OS_CREDENTIAL';

  • PASSO 2: Creazione di un job di test minimo
SELECT TO_CHAR(SYSDATE,'YYYYMMDDHH24:MI:SS') FROM DUAL;
-- occorre per determinare l'orario di inizio test--
BEGIN
 DBMS_SCHEDULER.CREATE_JOB (
    job_name            => 'TEST_CREDENTIAL',
    job_type            => 'EXECUTABLE',
    job_action          => '/bin/echo',
    number_of_arguments => 1,
    credential_name     => 'OS_CREDENTIAL',
    enabled             => FALSE
  );
  
  DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
    job_name          => 'TEST_CREDENTIAL',
    argument_position => 1,
    argument_value    => 'Test credential OK'
  );
  
  DBMS_SCHEDULER.ENABLE('TEST_CREDENTIAL');
  
  -- Esegue il job appena creato come utente METADATA_GEST
  DBMS_SCHEDULER.RUN_JOB('TEST_CREDENTIAL', FALSE);
END;

  • PASSO 3: Verifica il risultato (dopo 5-10 secondi)
SELECT 
    owner,job_name,status,log_date,additional_info, error#
FROM user_scheduler_job_run_details
WHERE job_name = 'TEST_CREDENTIAL'
ORDER BY log_date DESC
FETCH FIRST 1 ROWS ONLY;
  • PASSO 4: Interpreta il risultato della query relativa al passo 3
Se STATUS = 'SUCCEEDED' → Credential corretta
Se STATUS = 'FAILED' e ERROR# = 27369 → Password errata o utente non esiste
Se STATUS = 'FAILED' e ERROR# = 27486 → Privilegi insufficienti
  • PASSO 5: Cleanup
BEGIN
  DBMS_SCHEDULER.DROP_JOB('TEST_CREDENTIAL', force => TRUE);
END;
/

=========================
-- TEST JOB_TEST_CRT_SQL
=========================
  • PASSO 1: Drop e Creazione del job External che esegue lo script sql
      • in input i parametri P1 e P2
      • utente proprietario e che esegue il JOB METADATA_GEST
BEGIN
    DBMS_SCHEDULER.DROP_JOB(job_name =>
                                '"METADATA_GEST"."JOB_TEST_CRT_SQL"',
                                defer => false,
                                force => true);
END;

BEGIN
  DBMS_SCHEDULER.CREATE_JOB (
    job_name            => 'JOB_TEST_CRT_SQL',
    job_type            => 'EXECUTABLE',
    job_action          => '/bin/bash',
    number_of_arguments => 2,
    credential_name     => 'OS_CREDENTIAL',
    enabled             => FALSE,
    auto_drop           => FALSE,
    comments            => 'Esegue test.sql con parametri P1 e P2'
  );
END;
  • PASSO 2: Impostazione degli argomenti del job
    • Il flag -c indica a bash di eseguire il comando che segue come stringa.
      • Spiegazione:
        • bash/bin/bash -c "comando da eseguire"
        • c = "command" - dice a bash di leggere ed eseguire i comandi dalla stringa che segue. Senza -c, bash si aspetterebbe il nome di un file script da eseguire
    • --Nel nostro caso:
      • Argomento 1: il programma da eseguire  job_action => '/bin/bash'
      • Argomento 2: flag che dice "esegui il comando che segue" argument 1 => '-c'
      • Argomento 3: il comando vero e proprio
        • argument 2 => 
          • 'sqlplus -S username/password@TNS @/dire/test/test.sql "P1" "P2"'
    • Risultato finale è come avere la seguente stringa da eseguire da filesystem
      • /bin/bash -c 'sqlplus -S username/password@TNS @/dire/test/test.sql "P1" "P2"'
BEGIN
-- Argomento 1: flag -c per bash
  DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
    job_name          => 'JOB_TEST_CRT_SQL',
    argument_position => 1,
    argument_value    => '-c'
  );
    • Argomento 2: comando completo con sqlplus e parametri
      • Modificare i parametri P1 e P2 senza ricreare il job
      • Per vedere l'output di sqlplus su filesystem si può aggiungere un logging unix:
  DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
    job_name          => 'JOB_TEST_CRT_SQL',
    argument_position => 2,
    argument_value    => '/opt/oracle/product/23ai/dbhomeFree/bin/sqlplus -s                              A00/oracle@FREEPDB1 
                        @/opt/sched_cdd/wrapper_0.0/sql/TESTCRT_2_parametri.sql                                                 "VALORE_P1" "VALORE_P2"'
   );
   END;
/

  • Se dopo l'esecuzione dovessimo ricevere un errore SP2-0667 allora occorre settare le variabili di ambiente dell'ORACLE_HOME e quindi modificare quanto indicato sopra in:

SET DEFINE OFF;
BEGIN
  DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
    job_name          => 'JOB_TEST_CRT_SQL',
    argument_position => 2,
    argument_value    => 'export ORACLE_HOME=/opt/oracle/product/23ai/dbhomeFree &&             
                          expot PATH=$ORACLE_HOME/bin:$PATH &&     
                          export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH &&
sqlplus -s A00/oracle@FREEPDB1 @/opt/sched_cdd/wrapper_0.0/sql/TESTCRT_2_parametri.sql "VALORE_P1" "VALORE_P2"'
  );
END;
/
  • Se dopo l'esecuzione riceviamo l'errore SP2-0546 allora tocca modificare lo script sql sostituendo &p1 ed &p2 con &1 ed &2 e rinomino il file sql da eseguire in TESTCRT_job.sql
[oracle@localhost ~]$ more /opt/sched_cdd/wrapper_0.0/sql/TESTCRT_job.sql 
DECLARE 
BEGIN

EXECUTE IMMEDIATE 'create table appo_wrapper_&1  as select * from cat ';
EXECUTE IMMEDIATE 'create table appo_wrapper_&2 as select * from cat ';

END;
/

SET DEFINE OFF;
BEGIN
  DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
    job_name          => 'JOB_TEST_CRT_SQL',
    argument_position => 2,
    argument_value    => 'export ORACLE_HOME=/opt/oracle/product/23ai/dbhomeFree && 
                          export PATH=$ORACLE_HOME/bin:$PATH && 
                          export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH && 
                            sqlplus -s A00/oracle@FREEPDB1 @/opt/sched_cdd/wrapper_0.0/sql/TESTCRT_job.sql
                            "VALORE_P1" "VALORE_P2"'
  );
END;

PL/SQL procedure successfully completed.

  •  PASSO : Abilita ed esegue il job

Verifichiamo l'orario di esecuzione cosi da verificarlo anche sulle tabelle di loh

SELECT TO_CHAR(SYSDATE,'YYYYMMDD HH24:MI:SS') data FROM DUAL;
DATA             
-----------------
20251118 18:41:58

BEGIN
  DBMS_SCHEDULER.ENABLE('JOB_TEST_CRT_SQL');
END;

PL/SQL procedure successfully completed.

  • PASSO : Verifica il risultato (dopo 5-10 secondi)
SELECT   owner,job_name,status,log_date,additional_info, output,error#
FROM    user_scheduler_job_run_details
WHERE job_name = 'JOB_TEST_CRT_SQL'
ORDER BY log_date DESC
FETCH FIRST 1 ROWS ONLY;

OWNER         JOB_NAME          STATUS     LOG_DATE                         ADDITIONAL_INFO                                     ERROR#      OUTPUT
------------- ----------------- ---------- -------------------------------- -------------------------------------------------- -----------  ----------------------------------------------------------------------------------------
METADATA_GEST JOB_TEST_CRT_SQL  SUCCEEDED  18-NOV-25 18:43:15,189036000 GMT EXTERNAL_LOG_ID="job_96768_80906",USERNAME="oracle"  0          
"old   4: EXECUTE IMMEDIATE 'create table appo_wrapper_&1  as select * from cat ';                             new   4: EXECUTE IMMEDIATE 'create table appo_wrapper_VALORE_P1  as select * from cat ';
 old   5: EXECUTE IMMEDIATE 'create table appo_wrapper_&2 as select * from cat ';
 new   5: EXECUTE IMMEDIATE 'create table appo_wrapper_VALORE_P2 as select * from cat ';   

  • PASSO : Interpretazione del risultato
Se STATUS = 'SUCCEEDED' → Credential corretta
Se STATUS = 'FAILED' e ERROR# = 27369 → Password errata o utente non esiste
Se STATUS = 'FAILED' e ERROR# = 27486 → Privilegi insufficienti
Se STATUS = 'FAILED' e EXTERNAL_LOG_ID="job_96768_80884",
            ORA-27369: job of type EXECUTABLE failed with exit code: 1 Error 6 initializing SQL*Plus
            SP2-0667: Message file sp1<lang>.msb not found
            STANDARD_ERROR="Error 6 initializing SQL*Plus
            SP2-0667: Message file sp1<lang>.msb not found
            SP2-0750: You may need to set ORACLE_HOME to your Oracle software directory
            → settare le variabili di ambiente
Se STATUS = 'FAILED' e "Enter value for p1: 
            SP2-0546: User requested Interrupt or EOF detected.
            Help: https://docs.oracle.com/error-help/db/sp2-0546/"
            
  • PASSO : Verifica sul DB
SELECT * FROM CAT where table_name like 'APPO%'

TABLE_NAME                TABLE_TYPE 
------------------------- -----------
APPO_WRAPPER_VALORE_P1    TABLE      
APPO_WRAPPER_VALORE_P2    TABLE      

Di seguito le query di controllo delle esecuzione dei diversi job e verifiche varie:

======================
-- GESTIONE DEL JOB
======================
-- Per eseguire immediatamente il job (test manuale)
BEGIN
  DBMS_SCHEDULER.RUN_JOB(
    job_name => 'JOB_TEST_CRT_SQL',
    use_current_session => FALSE
  );
END;
/

-- Disabilitare il job
BEGIN
  DBMS_SCHEDULER.DISABLE('JOB_TEST_CRT_SQL');
END;
/

-- Eliminare il job
BEGIN
  DBMS_SCHEDULER.DROP_JOB(
    job_name => 'JOB_TEST_CRT_SQL',
    force    => TRUE
  );
END;
/

-- Eliminare la credential
BEGIN
  DBMS_SCHEDULER.DROP_CREDENTIAL('OS_CREDENTIAL');
END;
/

======================
-- Query DB oracle
======================

-- Verificare lo stato del job
SELECT job_name, state, enabled, last_start_date, next_run_date, failure_count
FROM user_scheduler_jobs
WHERE job_name = 'JOB_TEST_CRT_SQL';

-- Vedere il log delle esecuzioni
SELECT log_date, status, error#, additional_info
FROM user_scheduler_job_run_details
WHERE job_name = 'JOB_TEST_CRT_SQL'
ORDER BY log_date DESC;

-- Vedere i dettagli dell'output del job
SELECT log_date, owner,operation,status,credential_name,additional_info
FROM user_scheduler_job_log
WHERE job_name = 'JOB_TEST_CRT_SQL'
ORDER BY log_date DESC;

=================================
-- VERIFICA ESITO ESECUZIONE JOB
=================================

-- 1. Stato corrente del job
SELECT 
    job_name,
    state,              -- SCHEDULED, RUNNING, COMPLETED, etc.
    enabled,
    last_start_date,
    last_run_duration,
    next_run_date,
    run_count,
    failure_count
FROM user_scheduler_jobs
WHERE job_name = 'JOB_TEST_CRT_SQL';

-- 2. Storico delle esecuzioni (dettagliato)
SELECT 
    log_id,
    log_date,
    job_name,
    status,             -- SUCCEEDED, FAILED, STOPPED, etc.
    error#,
    additional_info
FROM user_scheduler_job_run_details
WHERE job_name = 'JOB_TEST_CRT_SQL'
ORDER BY log_date DESC
FETCH FIRST 10 ROWS ONLY;

-- 3. Log completo con output
SELECT 
    log_date,
    status,
    req_start_date,
    actual_start_date,
    run_duration,
    cpu_used
FROM user_scheduler_job_log
WHERE job_name = 'JOB_TEST_CRT_SQL'
ORDER BY log_date DESC;

-- 4. Se il job è FALLITO, vedi i dettagli dell'errore
SELECT 
    log_date,
    status,
    error#,
    additional_info
FROM user_scheduler_job_run_details
WHERE job_name = 'JOB_TEST_CRT_SQL'
AND status = 'FAILED'
ORDER BY log_date DESC;

-- 5. Verifica se il job è in esecuzione in questo momento
SELECT 
    job_name,
    session_id,
    running_instance,
    elapsed_time,
    cpu_used
FROM user_scheduler_running_jobs
WHERE job_name = 'JOB_TEST_CRT_SQL';

-- 6. Output dettagliato del job (se configurato)
SELECT 
    *
FROM user_scheduler_job_log
WHERE job_name = 'METADATA_GEST.JOB_TEST_CRT_SQL'
ORDER BY log_date DESC;

--Interpretazione dei risultati:

--STATUS = 'SUCCEEDED' → Esecuzione completata con successo
--STATUS = 'FAILED'    → Esecuzione fallita (guarda error# e additional_info)
--STATUS = 'STOPPED'   → Job interrotto manualmente
--STATE  = 'RUNNING'   → Job in esecuzione ora
--STATE  = 'SCHEDULED' → Job in attesa della prossima esecuzione


-- 1. Verifica il dettaglio completo dell'errore
SELECT 
    log_date,
    status,
    error#,
    additional_info,
    actual_start_date
FROM user_scheduler_job_run_details
WHERE job_name = 'JOB_TEST_CRT_SQL'
ORDER BY log_date DESC
FETCH FIRST 1 ROWS ONLY;

"EXTERNAL_LOG_ID="job_96755_80368",
ORA-27369: job of type EXECUTABLE failed with exit code: 127 /bin/bash: sqlplus: command not found
STANDARD_ERROR="/bin/bash: sqlplus: command not found
""

-- 2. Verifica se la CREDENTIAL è valida
SELECT 
 credential_name,    username,    comments
FROM user_scheduler_credentials
WHERE credential_name = 'OS_CREDENTIAL';


giovedì 23 ottobre 2025

ODI 14 - AGENT - Runtime Logging

 Per aumentare il livello di logging di un agent ODI occorre modificare alcuni parametri presenti nei file di configurazione.

I seguenti componenti di ODI possono essere tracciati:

    • ODI Studio
    • ODI Java EE agents
    • ODI Standalone agents
    • ODI Standalone Colocated agents
  • ODI Studio
    •  Per il Local Agent che gira all'interno di ODI Studio, il servizio di debug è abilitato e i log vengono scritti in tabelle del repository ODI (SNP_SESSION_DBG). 
    • La configurazione dei log a livello di ODI Studio avviene tramite il file ODI-logging-config.xml nella cartella del client ODI, dove è possibile impostare il livello trace per una registrazione dettagliata degli eventi.
  • Log Level
    • Il livello di log in Oracle Data Integrator (ODI) può essere impostato sugli elementi log_handler e/o logger nel file di configurazione dei log. La logica per la registrazione dei messaggi è la seguente:
      • Se il livello è impostato su un log_handler, allora si applica a tutti gli usi di quel log_handler.
      • Se il livello è impostato su un logger, allora si applica a tutti i suoi handler e ai logger discendenti che non hanno un livello esplicito impostato.
                    Un messaggio viene registrato solo se il suo livello di log è maggiore o uguale sia al
                    livello del logger sia al livello del log_handler.
                    In pratica, per far sì che un messaggio venga scritto, esso deve superare
                    contemporaneamente la soglia minima impostata sul logger e quella sul log_handler
                    specificato.
                    Questo meccanismo permette un controllo granulare della verbosità del logging,
                    facilitando il monitoraggio e la diagnostica di ODI in modo flessibile e configurabile 
                    tramite il file ODI-logging-config.xml.?

                   

      1. Open the ODI logging system configuration file of the ODI component. Each component has its own configuration file: 
        • ODI Studio: 
          • $ODI_HOME/odi/studio/bin/ODI-logging-config.xml 
        • ODI Standalone agent:
          •  <DOMAIN_HOME>/config/fmwconfig/components/ODI/<INSTANCE_NAME>/ODI-loggingconfig.xml 
      2. Make sure that the path to your log files is a valid and existing path. 
        • For example: 
                                
                                Note the following concerning the log files path: 
        • If you are on Windows, the path could be for example:
          •  %ODI_HOME%\oracledi\agent\log\${LOG_FILE} 
        • You can use a relative path on Windows and Unix. 
                          3. Enable the logger and set the log level.