Writing to rotating log file via channels
First up, as I understand it, you want to write to log files, but avoid constant IO operations. That's understandable. What I struggle to understand, however, is why you wouldn't use the standard golang packages to do buffered writes? the bufio package has a buffered writer that does just that.

Seeing as this is a code review site, allow me to first address some aspects of your code that could do with some more work. A quick overview of these things:


Avoid using new(). It's more idiomatic, and flexible, to actually create a literal: new(ChatLog) => &amp;ChatLog{}. This has the advantage of offering the visual reminder that it's a pointer (&amp;), and allows you to initialze any exported fields.


This allows you to write the following:

cl := new(ChatLog)
cl.logDir = LogDir
cl.Protocol = Protocol
cl.Server = Server
cl.logChannel = make(chan map[string]string, MaxQueue)


As a oneliner:

cl := &amp;ChatLog{
    logDir: logDir,
    Protocol: Protocol,
    Server: Server,
    logChannel: make(chan map[string]string, MaxQueue),
}


That, to my eye looks a lot cleaner.
A similar thing can be said about your example usage snippet. make is a construct you use to create buffered channels, slices with a pre-set length and/or capacity. If you don't need to do that, you might just as well use a literal:

testEntry := make(map[string]string)
testEntry["Type"] = "PRIVMSG"
testEntry["Entity"] = "SomeUser"
testEntry["Content"] = "This is the message!"
testLog.AddEntry(testEntry)


Can be written as:

testLog.AddEntry(
    map[string]string{
        "Type": "PRIVMSG",
        "Entity": "SomeUser",
        "Content": "This is the message!",
    },
)


A lot cleaner, I'd say.


"Errors are values, just like any other" is an adage you might have heard. This is true, but when you're doing something quite fundamental like logging, it's a really, really bad idea to ignore errors. If your logging component fails, I'd argue the best thing to do at that point is simply to call it a day, and exit. It's a fatal error IMO.


This means, for example that in your Open function:

if err != nil {
    log.Println("Error opening file:", logFilename)
}
chatLog.logFile = f


You're using the standard log package to simply print out a line saying you couldn't open the log file, and then you happily go and assign what can only be a nil pointer to chatLog.logFile. The first time you try and log something, you'll get a runtime panic because you'll attempt to dereference a nil-pointer. What I'd do at that point is log the actual error value I received and call os.Exit(1) or something:

f, err := os.OpenFile(logFilename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
    log.Println("Failed to open logfile %v - %v", logFilename, err)
    os.Exit(1)
}
chatLog.logFile = f


Some other things to consider (quite urgently)


Your code is not thread-safe. You're exporting both RotateIfNeeded and Write. Neither of these functions actually lock. I can see why, but what could happen if, when someone calls the RotateIfNeeded function, which then decides to open a new log, and in that time your Write function reaches the chatLog.logFile.Sync call? You close the logFile before you open a new one. These operations aren't atomic, not by a long shot, and you've got no means of locking. This is a very risky thing to do.
For every message you read from the channel, you're currently comparing the file name to a on-the-spot generated name. Wouldn't it be so much easier to move the occasional checking of the file to a routine instead? Just have it generate a new name every Nms, compare and if needed, acquire a lock on the os.File pointer, rotate the log file, and release? Whilst doing that, you'd only need to lock and release the a mutex every time you actually write a message to the log, instead of comparing file names. This has the added benefit that, owing to using a mutex, resolves to a large extent the concurrency problems mentioned earlier.
The risk of using channels for logging: You're using channels to write to a log, instead of writing to a log directly. This clearly suggests the use of routines. Given this, you have to understand that you stand to loose a great deal of logs should your main func return before you've worked through the entire set of messages on the channel. What would happen in that case? You're losing information you were trying to log. Plain and simple. This is unacceptable.
Reinventing the wheel: Logging is something that can be implemented cheaply, and without requiring the use of a mutex, or essentially re-implementing a mature tool like logrotate. Why not write your logs to stdout or stderr, and pipe those streams to a log, that is managed by logrotate for you? KISS