Enrich Events with Geo IP Data in Python
Returns a copy of each event dictionary, enriched with a geo-location dict from a mock IP-to-geo lookup table, with a fallback for unknown IPs.
Python code
32 linesimport ipaddress
GEO_IP_DB = {
"192.168.1.10": {"country": "US", "city": "New York", "lat": 40.7128, "lon": -74.0060},
"10.0.0.5": {"country": "DE", "city": "Berlin", "lat": 52.5200, "lon": 13.4050},
"172.16.0.8": {"country": "JP", "city": "Tokyo", "lat": 35.6762, "lon": 139.6503},
}
EVENTS = [
{"id": 1, "ip": "192.168.1.10", "action": "login"},
{"id": 2, "ip": "10.0.0.5", "action": "download"},
{"id": 3, "ip": "8.8.8.8", "action": "ping"},
{"id": 4, "ip": "172.16.0.8", "action": "upload"},
]
def enrich_event(event: dict) -> dict:
"""Return a copy of the event, enriched with geo data if known."""
enriched = dict(event)
ip = event.get("ip", "")
geo = GEO_IP_DB.get(ip)
if geo is not None:
enriched["geo"] = geo
else:
enriched["geo"] = {"country": "UNKNOWN", "city": "UNKNOWN", "lat": None, "lon": None}
return enriched
if __name__ == "__main__":
for ev in EVENTS:
print(enrich_event(ev))
Output
{'id': 1, 'ip': '192.168.1.10', 'action': 'login', 'geo': {'country': 'US', 'city': 'New York', 'lat': 40.7128, 'lon': -74.006}}
{'id': 2, 'ip': '10.0.0.5', 'action': 'download', 'geo': {'country': 'DE', 'city': 'Berlin', 'lat': 52.52, 'lon': 13.405}}
{'id': 3, 'ip': '8.8.8.8', 'action': 'ping', 'geo': {'country': 'UNKNOWN', 'city': 'UNKNOWN', 'lat': None, 'lon': None}}
{'id': 4, 'ip': '172.16.0.8', 'action': 'upload', 'geo': {'country': 'JP', 'city': 'Tokyo', 'lat': 35.6762, 'lon': 139.6503}}
How it works
The function creates a shallow copy of the original event dict with dict(event) so the input isn't mutated. It then uses GEO_IP_DB.get(ip) to look up geo data; if found, it adds a geo key, otherwise it supplies a fallback dict with UNKNOWN placeholders. This pattern keeps enrichment side-effect-free and predictable, which is essential in data pipelines where events are processed in batches and original records may be needed later. The ipaddress import is present but unused in this example; in production you'd validate or normalize IPs before lookup.
Common mistakes
- Mutating the original event dict instead of returning a copy, causing side effects downstream.
- Assuming every IP exists in the lookup table and not handling missing keys with a fallback.
- Using `geo` as a direct reference to the DB dict, so later changes leak into the event data.
- Ignoring IP format variations like IPv6 or strings with port numbers before lookup.
Variations
- Use a real geo IP library like `geoip2` with a MaxMind database for production lookups.
- Lazy-load the geo DB from a file or environment variable to avoid hardcoding in code.
Real-world use cases
- Adding geographic metadata to security log events for regional threat analysis.
- Enriching clickstream events with user location before storing in a data warehouse.
- Populating dashboard events with city and country info for real-time traffic maps.
Sponsored
More from Data pipelines & processing
- Add a UUID Surrogate Key to Each Row in a CSV with Python easy
- Attach Source File Metadata to Records in Python easy
- Build a Python Utility That Detects Duplicate Records Across Multiple Excel Sheets medium
- Check Null Rate Threshold in PySpark DataFrame medium
- Count Records Processed per Category in Python easy
- Create Data Helper Functions in Python for Beginners easy
Keep learning
Related tutorials and quizzes for this topic.