Skip to main content

Dear community,

 

 

My aim is to use FME desktop 2015 in our back-end infrastructure to perform quality control (QC) for data which remote users will be uploading to our server using our front-end infrastructure. To inform the users who upload the data on preliminary QC measures (i.e. are all necessary files present in a *.zip file which represents ESRI SHAPE?) I need to:

(a) Collect the error and warn messages produced during the preliminary QC translation

(b) Write the collected error and warn messages into a database table.

(c) Use the data stored in the database table to dynamically inform the users on the fly on whether they need to re-upload the data (i.e. failed preliminary QC), or the data are good to go the next stage (i.e. passed QC).

I want to achieve (a), and (b) using FME.

I would appreciate any insights!

I suspect, that this may need to be done as a post process where you run a separate workspace to read the .log file using the text file reader and parse out the lines beginning with "ERROR" and "WARN" and then load those to the database. If no one else comes back with a better method let me know and I'll post further details.

In the mean time, also take a look at the FME Store transformer the MessageLogger that I wrote a while back. This is helpful when you'd like to send user configured Errors or Warnings to the log file, rather than just ones created by FME. This maybe handy when features do not conform to your own rules rather than just failing rules defined in say the GeometryValidator.

All the best, Dave


Using fmeobjects, it is possible to define a user function that is called for every line that is output to the FME log. You could take advantage of this to capture and filter the messages based on the severity, then write those lines to the database e.g. using the FMEUniversalWriter object (if it's Oracle it might even be easier to write it directly using the cx_Oracle Python module).

Example startup script:

from fmeobjects import *
def LogSkimmer(severity, text):
    if severity in (FME_WARN, FME_ERROR):
        # Write the 'text' object to the database here...
FMELogFile().setCallBack(LogSkimmer)

David


Using fmeobjects, it is possible to define a user function that is called for every line that is output to the FME log. You could take advantage of this to capture and filter the messages based on the severity, then write those lines to the database e.g. using the FMEUniversalWriter object (if it's Oracle it might even be easier to write it directly using the cx_Oracle Python module).

Example startup script:

from fmeobjects import *
def LogSkimmer(severity, text):
    if severity in (FME_WARN, FME_ERROR):
        # Write the 'text' object to the database here...
FMELogFile().setCallBack(LogSkimmer)

David

Thanks @david_r, this is the kind of solution I was looking for. Will be using the FMEUniversalWriter object since I will be writing the data into PostgreSQL. Will be returning in this question to document my experience with this method.


I suspect, that this may need to be done as a post process where you run a separate workspace to read the .log file using the text file reader and parse out the lines beginning with "ERROR" and "WARN" and then load those to the database. If no one else comes back with a better method let me know and I'll post further details.

In the mean time, also take a look at the FME Store transformer the MessageLogger that I wrote a while back. This is helpful when you'd like to send user configured Errors or Warnings to the log file, rather than just ones created by FME. This maybe handy when features do not conform to your own rules rather than just failing rules defined in say the GeometryValidator.

All the best, Dave

Hi David,

 

Thanks for your input. My initial thought was to perform the log reading in a post-translation process as you suggest as well; possibly using Python or a separate workspace. It seems that @david_r method may be able to do what I am trying to achieve. Will keep you posted!

Using fmeobjects, it is possible to define a user function that is called for every line that is output to the FME log. You could take advantage of this to capture and filter the messages based on the severity, then write those lines to the database e.g. using the FMEUniversalWriter object (if it's Oracle it might even be easier to write it directly using the cx_Oracle Python module).

Example startup script:

from fmeobjects import *
def LogSkimmer(severity, text):
    if severity in (FME_WARN, FME_ERROR):
        # Write the 'text' object to the database here...
FMELogFile().setCallBack(LogSkimmer)

David

Using the LogSkimmer function I was able to collect the log file errors and print them in the FME log window but I haven't been able yet to create a feature using the text object (type string) every time that a "WARN" or "ERROR" is found.

I am receiving the following Python error in my FME log window:

(__main__:26: RuntimeWarning: tp_compare didn't return -1 or -2 for exception) 

when I am running the following functions:

from fmeobjects import *

def log_skimmer(severity,text):

    if severity in (FME_WARN,FME_ERROR):

        feature = FMEFeature()
        
#THIS IS WHERE I AM GETTING THE ERROR AT
feature.setattribute("MESSAGE_TEXT",text)
    
    return feature
        
###RUN FUNCTIONS###
FMELogFile().setCallBack(log_skimmer)

IMPORTANT UPDATE: This could be well a bug; I have tested other methods of the feature that I am creating using FMEFeature() when the if statement evaluates to "True" including setAttributeNullWithType(), setFeatureType(featureType), and setGeometryType(geomType) and they seem to work fine. It seems that the error is produced when I am using the setAttribute(attrName, attrValue) method.


Using the LogSkimmer function I was able to collect the log file errors and print them in the FME log window but I haven't been able yet to create a feature using the text object (type string) every time that a "WARN" or "ERROR" is found.

I am receiving the following Python error in my FME log window:

(__main__:26: RuntimeWarning: tp_compare didn't return -1 or -2 for exception) 

when I am running the following functions:

from fmeobjects import *

def log_skimmer(severity,text):

    if severity in (FME_WARN,FME_ERROR):

        feature = FMEFeature()
        
#THIS IS WHERE I AM GETTING THE ERROR AT
feature.setattribute("MESSAGE_TEXT",text)
    
    return feature
        
###RUN FUNCTIONS###
FMELogFile().setCallBack(log_skimmer)

IMPORTANT UPDATE: This could be well a bug; I have tested other methods of the feature that I am creating using FMEFeature() when the if statement evaluates to "True" including setAttributeNullWithType(), setFeatureType(featureType), and setGeometryType(geomType) and they seem to work fine. It seems that the error is produced when I am using the setAttribute(attrName, attrValue) method.

Hi

I'm not sure you're allowed to create FMEFeature objects inside the callback function, at least that's not how I understand this to work. Also, your usage of the FMEUniversalWriter above does not make much sense to me,  it looks very incomplete.

I think might be better off installing and using psycopg2 module to write directly to posgresql and skipping the FMEUniversalWriter altogether.

David


Hi

I'm not sure you're allowed to create FMEFeature objects inside the callback function, at least that's not how I understand this to work. Also, your usage of the FMEUniversalWriter above does not make much sense to me, it looks very incomplete.

I think might be better off installing and using psycopg2 module to write directly to posgresql and skipping the FMEUniversalWriter altogether.

David

Hi David,

 

 

Thanks for your reply. The universal writer function structure is just created in the code; I haven't ran it yet because I wasn't able to create the feature that I am trying to write in the database table. You are right though; that is misleading. The idea though is that after the feature has been created then I write the feature in the table using the write(feature) method.

 

 

I thought that any function could be used inside the callback function.

 

 

I would like to avoid using psycopg2 since our IT infrastructure is fixed and I also aim to achieve this using only FME (although I have functions that can do the job using psycopg2 and would definitely save me some time).

Hi David,

 

 

Thanks for your reply. The universal writer function structure is just created in the code; I haven't ran it yet because I wasn't able to create the feature that I am trying to write in the database table. You are right though; that is misleading. The idea though is that after the feature has been created then I write the feature in the table using the write(feature) method.

 

 

I thought that any function could be used inside the callback function.

 

 

I would like to avoid using psycopg2 since our IT infrastructure is fixed and I also aim to achieve this using only FME (although I have functions that can do the job using psycopg2 and would definitely save me some time).

If you cannot install psycopg2, you could perhaps write the interesting log lines to a global Python list object, which you then access in your shutdown script. It ought to be safe to use the FMEUniversalWriter there.


Using the LogSkimmer function I was able to collect the log file errors and print them in the FME log window but I haven't been able yet to create a feature using the text object (type string) every time that a "WARN" or "ERROR" is found.

I am receiving the following Python error in my FME log window:

(__main__:26: RuntimeWarning: tp_compare didn't return -1 or -2 for exception) 

when I am running the following functions:

from fmeobjects import *

def log_skimmer(severity,text):

    if severity in (FME_WARN,FME_ERROR):

        feature = FMEFeature()
        
#THIS IS WHERE I AM GETTING THE ERROR AT
feature.setattribute("MESSAGE_TEXT",text)
    
    return feature
        
###RUN FUNCTIONS###
FMELogFile().setCallBack(log_skimmer)

IMPORTANT UPDATE: This could be well a bug; I have tested other methods of the feature that I am creating using FMEFeature() when the if statement evaluates to "True" including setAttributeNullWithType(), setFeatureType(featureType), and setGeometryType(geomType) and they seem to work fine. It seems that the error is produced when I am using the setAttribute(attrName, attrValue) method.

The following works:

from fmeobjects import *

def log_skimmer(severity,text):

    if severity in (FME_WARN,FME_ERROR):

        feature = FMEFeature()


#THE FOLLOWING WORKS AND NO ERROR IS PRODUCED; It turns out you need to convert the text object into a method acceptable 'type' as documented into the fmeobjects API (e.g. unicode, string etc). However the text object is type string already (odd).

feature.setattribute("MESSAGE_TEXT",unicode(text))
    
    return None
        
###RUN FUNCTIONS###
FMELogFile().setCallBack(log_skimmer)

If you're able to use FME 2016, we've got a new LogMessageStreamer transformer for you http://docs.safe.com/fme/2016.0/html/FME_Desktop_Documentation/FME_Transformers/Transformers/LogMessageStreamer.htm


Hi @daleatsafe,

 

 

That is great news! Unfortunately, I cannot access FME 2016 though and it is unlikely that we will be upgrading soon.

Unfortunately I was not able to write the "WARN" and "ERROR" information skimmed by the "Translation Log" into a database table using the FMEUniversalWriter Class. I managed though to write the log data into a *.csv and a *.txt using the python csv module or the python write method respectively which in the first instance may fit the purpose of what I am trying to achieve.

Code is following:

from fmeobjects import *
import csv

def log_skimmer(severity,text):
   
    if severity in (FME_WARN,FME_ERROR):
        csv_row =  str(text),str(severity)]
        with open('C:\\log.csv','a') as csv_file:
            csv_writer = csv.writer(csv_file,delimiter=',')
            csv_writer.writerow(csv_row)

    return None

FMELogFile().setCallBack(log_skimmer)

The FMEUniversalWriter Class seems very promising though and deserves some additional documentation including commented examples to assist the community better understand it and use it in startup & shutdown scripts.

This answer has been accepted as "best answer" because it describes a more complete method for tackling the problem described in the fist post in this topic; It is only because of @david_r contribution of the log_skimmer() function and the clear explanation of the setCallBack() function that made the answer possible.


Unfortunately I was not able to write the "WARN" and "ERROR" information skimmed by the "Translation Log" into a database table using the FMEUniversalWriter Class. I managed though to write the log data into a *.csv and a *.txt using the python csv module or the python write method respectively which in the first instance may fit the purpose of what I am trying to achieve.

Code is following:

from fmeobjects import *
import csv

def log_skimmer(severity,text):
   
    if severity in (FME_WARN,FME_ERROR):
        csv_row =  str(text),str(severity)]
        with open('C:\\log.csv','a') as csv_file:
            csv_writer = csv.writer(csv_file,delimiter=',')
            csv_writer.writerow(csv_row)

    return None

FMELogFile().setCallBack(log_skimmer)

The FMEUniversalWriter Class seems very promising though and deserves some additional documentation including commented examples to assist the community better understand it and use it in startup & shutdown scripts.

This answer has been accepted as "best answer" because it describes a more complete method for tackling the problem described in the fist post in this topic; It is only because of @david_r contribution of the log_skimmer() function and the clear explanation of the setCallBack() function that made the answer possible.

I agree that the FMEUniversalWriter isn't for the faint of heart... However, you will find some examples if you search around in here.

Tip: Use the FMEDialog.destPrompt() method to find the necessary directives for your FMEUniversalWriter!


Reply