Since SQL Server 2005 came out, it has been much easier to audit changes to the structure of the database using Database Level Triggers, like this one:
CREATE TRIGGER [Audit] ON database
FOR DDL_DATABASE_LEVEL_EVENTS
AS
DECLARE @data XML
DECLARE @cmd NVARCHAR(max)
DECLARE @posttime NVARCHAR(24)
DECLARE @spid NVARCHAR(6)
DECLARE @loginname NVARCHAR(100)
DECLARE @hostname NVARCHAR(100)
SET @data = EVENTDATA()
SET @cmd = @data.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'NVARCHAR(max)')
SET @cmd = LTRIM(RTRIM(REPLACE(@cmd,'','')))
SET @posttime = @data.value('(/EVENT_INSTANCE/PostTime)[1]', 'NVARCHAR(24)')
SET @spid = @data.value('(/EVENT_INSTANCE/SPID)[1]', 'nvarchar(6)')
SET @loginname = @data.value('(/EVENT_INSTANCE/LoginName)[1]',
'NVARCHAR(100)')
SET @hostname = HOST_NAME()
INSERT INTO auditlog.dbo.AuditLog(Command, PostTime,HostName,LoginName, DatabaseName)
VALUES(@cmd, @posttime, @hostname, @loginname, db_name())
GO
Now, some people would have the table storing the changes contained within the database but I needed a quick reference point for several databases on a development server so I decided to store the data in separate database. Unfortunately, I forgot to add a DatabaseName column, something I realized soon after I started, so I added the column and then went and modified the database triggers to include that information (as seen in the CREATE above).
Interestingly enough, this appears to be an After Trigger, as each of the entries for this trigger included the database name.
Which, I suppose, makes sense, since the change needs to be applied without any errors before it is stored as a change.