I agree with answers above: you generally don't need micro-optimizations, especially with high-level languages with optimizing compilers.
However, I want to add one more, slightly lower point of view.
Let's pretend (almost)all optimizations are OFF and find out what machine code we end up with:
In case 1:
When logMode is false, we end up just with one jump instruction (branch on if) and proceed right to useful work
When logMode is true, we end up with at least three jumps (branch + call + return) and executing whatever inside log() function
In case 2:
logMode state, we have at least two jumps (call + return) and whatever inside function we calling (that our noop function is empty doesn't means it produces no code). (and also pointer adds indirection)Real examples (built with `gcc -c -O0 testX.c -o testX`):
test1.c:
    #include <stdio.h>
    void log(void) { printf("Hello\n"); }
    int main(int argc, char **argv)
    {
        int logMode = 0;
        int result;
        while (1) {
            if (logMode == 1) {
                log();
            }
            result = 1; /* simulate useful work */
        }
        return result;
    }
test1 disassembly fragment:
    ...
    0000000000000016 <main>:
      16:   55                      push   %rbp
      17:   48 89 e5                mov    %rsp,%rbp
      1a:   48 83 ec 20             sub    $0x20,%rsp
      1e:   89 7d ec                mov    %edi,-0x14(%rbp)
      21:   48 89 75 e0             mov    %rsi,-0x20(%rbp)
      25:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
    /* start of loop */
      2c:   83 7d fc 01             cmpl   $0x1,-0x4(%rbp) /* compare `logMode` to `1` */
      30:   75 05                   jne    37 <main+0x21>  /* if `false`, jump directly to "useful work" (37) */
      32:   e8 00 00 00 00          call   37 <main+0x21>  /* call log */
      37:   c7 45 f8 01 00 00 00    movl   $0x1,-0x8(%rbp) /* "useful work" */
      3e:   eb ec                   jmp    2c <main+0x16>  /* back to start of the loop */
    ...
test2.c:
    #include <stdio.h>
    void log(void) { printf("Hello\n"); }
    void noop(void) { /* nothing here */ }
    void (*func_ptr)(void);
    int main(int argc, char **argv)
    {
        int logMode = 0;
        int result;
        if(logMode == 1){
            func_ptr = log;
        } else {
            func_ptr = noop;
        }
        while (1) {
            func_ptr();
            result = 1; /* simulate useful work */
        }
        return result;
    }
test2 disassembly fragment:
    ...
    0000000000000016 <noop>:        /* here's five lines of our "empty" function */
      16:   55                      push   %rbp
      17:   48 89 e5                mov    %rsp,%rbp
      1a:   90                      nop
      1b:   5d                      pop    %rbp
      1c:   c3                      ret
    
    000000000000001d <main>:
      1d:   55                      push   %rbp
      1e:   48 89 e5                mov    %rsp,%rbp
      21:   48 83 ec 20             sub    $0x20,%rsp
      25:   89 7d ec                mov    %edi,-0x14(%rbp)
      28:   48 89 75 e0             mov    %rsi,-0x20(%rbp)
      2c:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
      33:   83 7d fc 01             cmpl   $0x1,-0x4(%rbp)
      37:   75 10                   jne    49 <main+0x2c>
      39:   48 8d 05 00 00 00 00    lea    0x0(%rip),%rax
      40:   48 89 05 00 00 00 00    mov    %rax,0x0(%rip)
      47:   eb 0e                   jmp    57 <main+0x3a>
      49:   48 8d 05 00 00 00 00    lea    0x0(%rip),%rax
      50:   48 89 05 00 00 00 00    mov    %rax,0x0(%rip)
    /* start of loop */
      57:   48 8b 05 00 00 00 00    mov    0x0(%rip),%rax   /* loading function pointer from memory into register */
      5e:   ff d0                   call   *%rax            /* calling function regardless we want logs */ 
      60:   c7 45 f8 01 00 00 00    movl   $0x1,-0x8(%rbp)  /* useful work */
      67:   eb ee                   jmp    57 <main+0x3a>   /* back to start of the loop */
    ...