How can I tell I'm affected?
This is probably the first question to those not familiar with this topic. With Gingerbread (Android 2.3) and above, you've got a service aboard helping you to figure out: battery statistics. Though manufacturers tend to place it at different points, it's mostly found in Settings → About the phone → Battery or similar, and shows a list of the apps having used most of your battery. On top of that is a small graph. Tap that, and it brings you to a screen similar to this one:
Screenshot of battery statistics on Android 2.3
I chose a screenshot from one of my devices which illustrates the issue. Looking at the lower two blue bars ("Aktiv" = Device was kept awake (active), "Bildschirm an" = "Screen on"), the right-most blue bar on "Aktiv" indicates a WakeLock: Device was kept busy despite the fact the screen was turned off. So by this we can be pretty sure we've got a WakeLock -- but we cannot tell who caused it.
If your device does not offer this screen (or the bars at the bottom: I just discovered e.g. the LG Optimus 4X running Android 4.0.3 has cut these bars off), you can find them e.g. using GSam Battery Monitor:
Similar information from GSam Battery Monitor -- here the mentioned "blue bars" are yellow/orange
What caused the WakeLock?
Unfortunately, this question cannot be answered using pre-installed apps (except for, maybe, some Custom ROMs). But there are tools available that can. The best known candidate for this is BetterBatteryStats, and shows us the cause in its partial wakelocks section:
Screenshots from BetterBatteryStats
In the first example2 (taken from the app's playstore page), the event causing most of the WakeLocks was a desired one: We don't want the playback stopped while listening to music. So the second example3 (taken from a real case on one of my devices) might prove better: the topmost 3 events are caused by the very same app, which needed the WakeLock to keep the IMAP push service active.
For an alternative to BetterBatteryStats, check out the Wakelock Detector app mentioned in UzumApps' answer -- which seems easier to handle especially for non-techies:
Wakelock Detector -- Click image to enlarge. (Source: Google Play)
What can be done?
If the case is as clear as in the second example in the previous section, the action is quite obvious -- at least in my case: I don't need to be informed immediately when a mail arrives; a delay of 30min is absolutely acceptable. So I went into the mail app, disabled IMAP Push (see also: Push Email), and instead switched to a 30min poll interval. WakeLocks did not entirely disappear, but dropped markably -- battery life improved noticably.
Then there's the case mentioned in the question itself: A bad behaving app not releasing its WakeLock. Confront the dev with your findings and ask for a fix. If he delivers: problem solved. If not: There's almost always an alternative app available.
What if it is the Android System itself?
Yeah, sometimes it looks like just that: 98% or more consumed by some Android service. Oh, if it's 98%, in most cases the candidate is named LocationManagerService. Bad guy spying at us? Not necessarily. In this special case, the listed "bad guy" is not even guilty -- at least not directly. Here it is another app requesting the current location too frequently. There's an excellent article on Setera.org about this: Pinpointing Android LocationManagerService battery drain. To give an abstract: It uses Android's
dumpsys feature (requires root!) to dump a system state, and lets you investigate the listeners established for the LocationManagerService. A closer look at their configuration shows which are constantly "hammering" it for location info (some do so permanently, i.e. without a break). As the app's ID is listed along, and at another place in the dump even together with the apps technical name, you can still identify it and take appropriate actions.
And what about UFOs?
Unfortunately, there are such: Apps which registered a WakeLock -- and then exited without releasing it. What's left are Unused F**ing Obsoletes* -- WakeLocks held for no use. So no way to simply bring the app to foreground and re-configure, or making it release its WakeLocks.
Here the only solution known to me is a reboot -- and I would like to have a better solution. Of course, if you know the guilty app, the steps concerning it are the same as above: inform the dev, get a fix -- or replace the app. But about getting rid of the current WakeLock? Maybe somebody else can provide a better alternative to the reboot?
Are there some recommended further readings?
Sure. One for now, I may add more later: