Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6539371
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 25, 20262026-05-25T10:51:06+00:00 2026-05-25T10:51:06+00:00

I have a few custom logfunctions that are extensions of cat . A basic

  • 0

I have a few custom logfunctions that are extensions of cat. A basic example is something like this:

catt<-function(..., file = "", sep = " ", fill = FALSE, labels = NULL,
    append = FALSE)
{
    cat(..., format(Sys.time(), "(%Y-%m-%d %H:%M:%S)"), "\n", file = file, 
        sep = sep, fill = fill, labels = labels, append = append)
}

Now, I work a lot with (selfmade) functions, and use some of these logfuntions to see the progress, which works quite well. What I notice, though, is that I almost always use these functions like this:

somefunc<-function(blabla)
{
  catt("somefunc: start")
  #do some very useful stuff here
  catt("somefunc: some time later")
  #even more useful stuff
  catt("somefunc: the end")
}

Notice how every call to catt begins with the name of the function it is called from. Very neat until I start to refactor my code and rename functions etc.

Thanks to some old R-list post from Brian Ripley, if I’m not mistaken, I found this code to get the ‘current function name’:

catw<-function(..., file = "", sep = " ", fill = FALSE, labels = NULL,
    append = FALSE)
{
    curcall<-sys.call(sys.parent(n=1))
    prefix<-paste(match.call(call=curcall)[[1]], ":", sep="")
    cat(prefix, ..., format(Sys.time(), "(%Y-%m-%d %H:%M:%S)"), "\n",
        file = file, sep = sep, fill = fill, labels = labels, append = append)
}

This is very nice, but it doesn’t always work, because:

  • my functions are scattered with anonymous functions used in lapply
    type of functions, like this:
aFunc<-function(somedataframe)
{
  result<-lapply(seq_along(somedataframe), function(i){
  catw("working on col", i, "/", ncol(somedataframe))
  #do some more stuff here and return something
  return(sum(is.na(somedataframe[[i]])))
  }
}

-> for these cases, apparently (and understandably) I need n=3 in the sys.parent call in my catw function.

  • I occasionally use do.call: it appears my current implementation
    doesn’t work either (once again I can somewhat understand it, though
    I haven’t figured it out completely.

So, my question is: is there a way to find the first named function higher in the callstack (skipping the logging function itself, and maybe some other “wellknown” exceptions), which would allow me to write one single version of catw for all cases (so that I can happily refactor without worrying about my logging code)? How would you go about something like this?

Edit: these cases should be supported:

testa<-function(par1)
{
    catw("Hello from testa, par1=", par1)
    for(i in 1:2) catw("normal loop from testa, item", i)
    rv<-sapply(1:2, function(i){catw("sapply from testa, item", i);return(i)})
    return(rv)
}

testb<-function(par1, par2)
{
    catw("Hello from testb, par1=", par1)
    for(i in 1:2) catw("normal loop from testb, item", i)
    rv<-sapply(1:2, function(i){catw("sapply from testb, item", i);return(i)})

    catw("Will now call testa from testb")
    rv2<-testa(par1)
    catw("Back from testa call in testb")

    catw("Will now do.call testa from testb")
    rv2<-do.call(testa, list(par1))
    catw("Back from testa do.call in testb")

    return(list(rv, rv2))
}

testa(123)
testb(123,456)
do.call(testb, list(123,456))
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-25T10:51:06+00:00Added an answer on May 25, 2026 at 10:51 am

    EDIT : Complete rewrite of function

    The new version of this function uses the call stack, sys.calls(), rather than match.call.

    The call stack contains the complete calling function. So the trick now is to only extract the bits of it that you really want. I have resorted to a bit of manual cleanup in the clean_cs function. This evaluates the first word in the call stack and returns the desired argument for a small number of known edge cases, in particular lapply, sapply and do.call.

    The only downside of this approach is that it will return function names all the way to the top of the call stack. Perhaps a logical next step would be to compare these functions with a spefified environment/namespace and include/exclude function names based on that…

    I shall stop here. It answers to the use cases in the question.


    The new function:

    catw <- function(..., callstack=sys.calls()){
      cs <- callstack
      cs <- clean_cs(cs)
      #browser()
      message(paste(cs, ...))
    }
    
    clean_cs <- function(x){
      val <- sapply(x, function(xt){
        z <- strsplit(paste(xt, collapse="\t"), "\t")[[1]]
        switch(z[1],
            "lapply" = z[3], 
            "sapply" = z[3],
            "do.call" = z[2], 
            "function" = "FUN",
            "source" = "###",
            "eval.with.vis" = "###",
            z[1]
            )
        })
      val[grepl("\\<function\\>", val)] <- "FUN"
      val <- val[!grepl("(###|FUN)", val)]
      val <- head(val, -1)
      paste(val, collapse="|")
    }
    

    Test results:

    testa Hello from testa, par1= 123
    testa normal loop from testa, item 1
    testa normal loop from testa, item 2
    testa sapply from testa, item 1
    testa sapply from testa, item 2
    
    
    testb Hello from testb, par1= 123
    testb normal loop from testb, item 1
    testb normal loop from testb, item 2
    testb sapply from testb, item 1
    testb sapply from testb, item 2
    testb Will now call testa from testb
    testb|testa Hello from testa, par1= 123
    testb|testa normal loop from testa, item 1
    testb|testa normal loop from testa, item 2
    testb|testa sapply from testa, item 1
    testb|testa sapply from testa, item 2
    testb Back from testa call in testb
    testb Will now do.call testa from testb
    testb|testa Hello from testa, par1= 123
    testb|testa normal loop from testa, item 1
    testb|testa normal loop from testa, item 2
    testb|testa sapply from testa, item 1
    testb|testa sapply from testa, item 2
    testb Back from testa do.call in testb
    
    
    testb Hello from testb, par1= 123
    testb normal loop from testb, item 1
    testb normal loop from testb, item 2
    testb sapply from testb, item 1
    testb sapply from testb, item 2
    testb Will now call testa from testb
    testb|testa Hello from testa, par1= 123
    testb|testa normal loop from testa, item 1
    testb|testa normal loop from testa, item 2
    testb|testa sapply from testa, item 1
    testb|testa sapply from testa, item 2
    testb Back from testa call in testb
    testb Will now do.call testa from testb
    testb|testa Hello from testa, par1= 123
    testb|testa normal loop from testa, item 1
    testb|testa normal loop from testa, item 2
    testb|testa sapply from testa, item 1
    testb|testa sapply from testa, item 2
    testb Back from testa do.call in testb
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a few custom UITableViewCells - http://img11.imageshack.us/i/customfacilitiescell.png/ which are added to this UIViewController
I have written a few MSBuild custom tasks that work well and are use
I have a simple C++ DLL that implements a few custom actions for a
I have created a small flash CS4 project that has a few custom components
In a word, how? I have a view controller that creates a few custom
I have a few models that need to have custom find conditions placed on
I have a few custom form validation rules I wish to apply. Things like
I have built a few custom applications that run on WSS 3 using the
I have a few custom tables in my Drupal database that were created manually.
I have developed a custom visual basic 6 control and declared a few custom

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.